tom*_*tom 3 c++ templates c++20
如果函数体没有意义(即不编译),我经常使用SFINAE从重载集中删除函数.是否可以向C++添加一个简单的require声明?
例如,让我们有一个功能:
template <typename T>
T twice(T t) {
return 2 * t;
}
Run Code Online (Sandbox Code Playgroud)
然后我得到:
twice(1.0);
twice("hello"); // Error: invalid operands of types ‘int’ and ‘const char*’ to binary ‘operator*’
Run Code Online (Sandbox Code Playgroud)
我想得到一个错误,说明没有twice类型参数的函数const char *
我想写点类似的东西:
template <typename T>
requires function_body_compiles
T twice(T t) {
return 2 * t;
}
Run Code Online (Sandbox Code Playgroud)
然后我会得到
twice(1.0);
twice("hello"); // Error: no matching function for call to ‘twice2(const char [6])’
Run Code Online (Sandbox Code Playgroud)
更多的动力:我正在观看关于琐碎类的移动语义的梦魇和他的最终SFINAE基本上说:在编译时使用这个构造函数.对于更复杂的构造函数来说,编写正确的SFINAE将是一场噩梦.
你认为添加requires function_body_compiles到c ++会有意义吗?还是我缺少一个根本问题?这会被滥用或滥用的严重程度如何?
我们没有这个功能的最大原因是它很难.
这很难,因为它要求编译器能够编译几乎任意的C++代码,获取错误,然后干净利落地退出.
现有的C++编译器并非都是为此而设计的.事实上,MSVC花了十年时间才能合理地符合decltypeSFINAE的支持.
对全功能机构这样做会更加困难.
现在,即使很容易,也有理由不这样做.它以非常可怕的方式混合了实现和界面.
而不是这样,C++委员会正朝着完全不同的方向前进.
概念是您可以通过合理的,通常命名的方式表达对类型的要求的想法.他们来的是c ++ 20.
另一个答案提到,
template <typename T> requires requires(T t) { { 2 * t } -> T; }
T twice(T t) {
return 2 * t;
}
Run Code Online (Sandbox Code Playgroud)
是一种方法,但这种方式被认为是不好的形式.相反,你应该写一个概念"可以乘以一个整数并返回相同的类型".
template<typename T>
concept IntegerScalable = requires(T t) {
{ 2 * t } -> T;
};
Run Code Online (Sandbox Code Playgroud)
我们可以
template <IntegerScalable T>
T twice(T t) {
return 2 * t;
}
Run Code Online (Sandbox Code Playgroud)
我们完成了.
期望的下一步称为"检查概念".在已检查的概念中,它将概念转换为您的类型的一组编译时接口T.
然后检查函数体,以确保T不对任何不是概念要求的类型做任何事情.
使用理论上未来检查的概念,
template <IntegerScalable T>
T twice(T t) {
T n = 7;
if (n > t) return n;
return 2 * t;
}
Run Code Online (Sandbox Code Playgroud)
即使在完成对模板的调用之前编译模板时,编译器也会拒绝这一点,因为这个概念IntegerScalable并不能保证你可以T用整数初始化a ,也不能用它T来比较>.另外我认为以上需要移动构造.
你今天可以做一个黑客攻击.
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
Run Code Online (Sandbox Code Playgroud)
然后你的代码可以写成:
template<class T>
T twice(T t)
RETURNS( 2 * t )
Run Code Online (Sandbox Code Playgroud)
你将得到一个SFINAE友好版本twice.它也将尽可能不受欢迎.
@Barry提出了一种=>用于替换RETURNS和其他东西的变体,但是自从我看到它移动已经过去了一年.
同时,RETURNS做了大部分繁重的工作.