val*_*ica 3 c++ templates c++17
我正在C ++ 17项目中,其中有以下定义(当然是在我的名称空间中):
using CppFunction = std::function<int(StatePtr&)>;
template<typename T>
using CppMethod = std::function<int(T*, StatePtr&)>;
Run Code Online (Sandbox Code Playgroud)
现在,我声明一些功能:
template<typename... Targs, typename F>
constexpr CppFunction CppFunctionNative(F func);
template<typename... Targs, typename F, typename T = (deducing class from F here) >
constexpr CppMethod<T> CppMethodNative(F func);
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是,第一个声明会导致编译器错误Constexpr function's return type is not a literal type
,但是第二个效果很好。
为什么会这样?它与第二个函数的返回类型是template的事实有关吗?
UPD:简化的独立示例:
#include <functional>
using CppFunction = std::function<int(int&)>;
template<typename T>
using CppMethod = std::function<int(T*, int&)>;
// Clang will complain
template<typename F>
constexpr CppFunction CppFunctionNative(F func) {};
// Clang will not complain
template<typename F, typename T = /*(deducing class from F here)*/char >
constexpr CppMethod<T> CppMethodNative(F func) {};
// main() function doesn't matter
int main() {
CppFunctionNative(0);
CppMethodNative(0);
return 0;
};
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是,第一个声明会导致编译器错误Constexpr函数的返回类型不是文字类型,但是第二个可以正常工作。
为什么会这样?它与第二个函数的返回类型是template的事实有关吗?
是。在第一种情况下,编译器可以证明的特定专业化std::function
不是文字类型。
在第二种情况下,它必须T
先知道的特定专长std::function
是否为文字类型。
template<class T>
struct example {
virtual T get() const {return {};}
~example() {}
};
template<>
struct example<int> {};
#if 0
template<class F>
constexpr example<double> test( F ) { return {}; }
#endif
template<class T, class F>
constexpr example<T> test2( F ) { return {}; }
Run Code Online (Sandbox Code Playgroud)
test
是非法的;test2
很好 其实test2<int>( 3.14 )
是合法的constexpr
。
现在,std::function
还没有这样的专业化,但这不是编译器需要证明的。这样做通常需要解决暂停问题,这是C ++标准试图避免要求编译器这样做的问题。
如@MaxLanghof所提到的,这种错误导致“格式错误,无需诊断”程序。不会强制编译器检测到您的constexpr
函数不能为constexpr
,但是如果您这样做,则编译器可以自由执行任何操作,包括生成错误消息(或更糟糕的事情)。
因此,GCC忽略错误并没有错,而clang发出错误也没有错。从某种意义上说,Clang的错误发出要比gcc的省略要高。