能否通过lambda将变量模板传递给函数?

3

我知道如何将模板函数作为模板参数传递,现在我正在尝试以类似的方式传递变量模板。

这是我尝试过的最小示例:

#define PASS_VARIABLE_TEMPLATE(name) [dummy=nullptr](auto&&...args) \
                                                    {return name<decltype(args)...>;}

//testing
template <typename T>
bool value = std::is_fundamental<T>::value;

template <typename Hax>
void print_bool(Hax h)
{
    std::cout << h(int{}) << std::endl; // no error, wrong output
    //std::cout << h(int{}, float{}) << std::endl; // error, good
}

int main()
{
    print_bool(PASS_VARIABLE_TEMPLATE(value)); //prints 0 instead of 1
}

演示

如果编译成功,为什么输出结果是错误的?


一个引用足够好吗? - lorro
@lorro 哦,我真是太傻了,忘记做衰减了!但另一方面,那会破坏引用/指针检查...应该也可以检查这种情况:int b; int& ref = a; h(ref); //类型为int& - xinaiz
你将通过以下代码获得预期结果:#define PASS_VARIABLE_TEMPLATE(name) [dummy=nullptr](auto&&args) { return name::type>; } - Sam Varshavchik
@SamVarshavchik 是的,但另一方面,如果应用std::is_rvalue_reference,它不会出错吗? - xinaiz
2个回答

3
您的代码主要问题在于,decltype 推导参数作为 rvalue 引用 (int&&),因为您的 lambda 使用 转发引用 接受参数。使用 裸类型std::is_fundamental 可以很好地解决问题。
对于您特定的代码片段,正确的解决方案是删除引用
#define PASS_VARIABLE_TEMPLATE(name) \
    [dummy=nullptr](auto&&...args){return name<std::remove_reference_t<decltype(args)>...>;}

现在它正常工作。 :-) 请在Coliru上直播查看。
稍微更通用或更好的方法是额外去除cv限定符。最终,您可能需要使用std::decay
#define PASS_VARIABLE_TEMPLATE(name) [dummy=nullptr](auto&&...args) \
{return name<std::decay_t<decltype(args)>...>;}

1
template<class T>struct tag_t{using type=T; constexpr tag_t(){}};
template<class Tag>using tagged_type=typename Tag::type;
template<class T>constexpr tag_t<T> tag{};

这些帮助将类型作为值传递并进行拆包。

#define PASS_VARIABLE_TEMPLATE(name) [](auto...args) \
                                                {return name<tagged_type<decltype(args)>...>;}

print_bool函数内部,你执行以下操作:
std::cout << h(tag<int>) << std::endl;

我不确定为什么要使用 dummy=nullptr 这个东西。

tag 作为模板可以无损地携带类型。


3
“dummy” 是由于 GCC 对于非捕获式 lambda 表达式的一个 bug 导致的(请查看我在问题中发布的链接中被接受的答案)。顺便说一下,这是一个很棒的解决方案。 - xinaiz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接