为什么这些模板化函数不能不带参数?
Why Can't These Templatized Functions Take No Arguments?
我正在尝试使用两个模板化函数来替换失败不是错误(SFINAE)。我可以这样做:
template<typename R, typename S = decltype(declval<R>().test())> static true_type Test(R*);
template<typename R> static false_type Test(...);
但我不明白这个论点是如何使这个SNFIAE发挥作用的。看起来我应该能够删除参数,模板选择将以完全相同的方式工作:
template<typename R, typename S = decltype(declval<R>().test())> static true_type Test();
template<typename R> static false_type Test();
但事实并非如此,我明白:
重载的"Test()"调用的不明确
这些论点是什么使SFINAE发挥作用的?
您的第二个示例编译失败,因为Test
有两个重载具有相同的签名,因为默认的模板类型参数不是函数签名的一部分。这是不允许的。
您的第一个示例以以下方式工作:
当类型R
中确实有函数test
时,两个Test
都成为有效的重载候选者。然而,省略号函数的秩比非省略号的函数低,因此编译器选择第一个重载,返回true_type
。
当R上没有test
时,第一个过载将从过载解析集中排除(SFINAE在工作)。只剩下第二个,它返回false_type
。
这个问题已经得到了回答,但深入解释可能会很有用。
希望这个带注释的程序能让事情变得更清楚:
#include <utility>
#include <iostream>
// define the template function Test<R> if and only if the expression
// std::declval<R>().test()
// is a valid expression.
// in which case Test<R, decltype(std::declval<R>().test())>(0) will be preferrable to... (see after)
template<typename R, typename S = decltype(std::declval<R>().test())>
static std::true_type Test(R*);
// ...the template function Test<R>(...)
// because any function overload with specific arguments is preferred to this
template<typename R> static std::false_type Test(...);
struct foo
{
void test();
};
struct bar
{
// no test() method
// void test();
};
// has_test<T> deduces the type that would have been returned from Test<T ... with possibly defaulted args here>(0)
// The actual Test<T>(0) will be the best candidate available
// For foo, it's Test<foo, decltype(std::declval<R>().test())>(foo*)
// which deduces to
// Test<foo, void>(foo*)
// because that's a better match than Test<foo>(...)
//
// for bar it's Test<bar>(...)
// because Test<bar, /*error deducing type*/>(bar*)
// is discarded as a candidate, due to SFNAE
//
template<class T>
constexpr bool has_test = decltype(Test<T>(0))::value;
int main()
{
std::cout << has_test<foo> << std::endl;
std::cout << has_test<bar> << std::endl;
}
相关文章:
- 如何反转整数参数包
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用默认参数等选择模板专业化
- 模板参数替换失败,并且未完成隐式转换
- 具有默认模板参数的多态类的模板推导失败
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 函数调用中参数的顺序重要吗
- 部分定义/别名模板模板参数
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- 使用不带参数的函数访问结构元素
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 如何使用Luacneneneba API正确读取字符串和表参数
- 在派生函数中指定void*参数
- 视图中的参数推导失败:take_while
- static_assert在宏中,但也可以扩展到可以用作函数参数的东西
- 为什么这些模板化函数不能不带参数?
- char* 具有内部链接,因此它不能不是非类型模板参数
- 为什么在推导模板参数时应用 §5/5?规则不能不同吗?