1

我有一个包含variant.

我想为该结构编写一个成员函数,该函数应该根据当前持有的类型变体运行代码。

但是,我在编译时遇到了问题。我不想使用更多的“模板恶作剧”,比如使用单独的结构来定义operator(T&),因为它更加污染了语法。这是一个例子:

struct Data {

std::variant<int, double> var;


//Into this function,multiple lambdas should be passed for cases that the user wants to handle
template<typename ... Funcs>
void apply(Funcs&&... funcs) {
    std::visit(std::forward<Funcs>(funcs)...,var);
}
};
int main() {
    Data d;
    d.var = 4;
    //variant holds int and lambda provided that takes int&, execute it:
    d.apply([](int& i){
        std::cout << "I am Int Poggers" << std::endl;
    });
    d.var = 0.0;
    //variant holds double but no lambda passed that takes a double, hence nothing happens:
    d.apply([](int& i){
        std::cout << "I am Int Poggers" << std::endl;
    });
}

我什至不知道编译器想从我这里得到什么: https ://godbolt.org/z/oM4584anf

4

1 回答 1

3

您的问题是std::visit()需要一个“访问者”来处理所有类型的std::variant.

但是,我在编译时遇到了问题。我不想使用更多的“模板恶作剧”,比如使用单独的结构来定义 operator(T&),因为它更加污染了语法。

没有什么复杂的。

您可以按如下方式简单地添加一个简单的结构(带有演绎指南)(并按照cppreference std::visit()page中的建议)

template<class... Ts> struct overloaded : Ts...
 { using Ts::operator()...; };

template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

然后,假设您想要std::visit()return void,您可以在您的apply()方法中添加一个通用的无操作 lambda

template<typename ... Funcs>
void apply(Funcs&&... funcs) {
    std::visit(overloaded{ // <-- pass through overloaded
               [](auto const &){}, // <-- and add this generic lambda
               std::forward<Funcs>(funcs)...},var);
}

现在第一个apply()电话

d.apply([](int& i){
    std::cout << "I am Int Poggers" << std::endl;
});

应该编译调用提供的 lambda,因为它是一个更好的匹配(给定d包含 a int),第二个调用编译调用不做任何事情的通用 lambda,因为通用 lambda 更适合 a double

于 2021-08-29T14:23:37.153 回答