std :: function,文字类型和模板

时间:2019-06-26 17:23:14

标签: c++ templates c++17

我正在研究C ++ 17项目,其中除其他定义外,这些定义(当然是在我的名称空间中):

using CppFunction = std::function<int(StatePtr&)>;

template<typename T>
using CppMethod = std::function<int(T*, StatePtr&)>;

现在我声明一些功能:

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);

令我惊讶的是,第一个声明会导致编译器错误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;
};

有趣的是,OnlineGDB和离线GCC 8.3.0对此没有抱怨,但是我的Clang 8对此有所抱怨。

2 个答案:

答案 0 :(得分:7)

  

令我惊讶的是,第一个声明会导致编译器错误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 {}; }

Live example

test是非法的; test2很好。实际上,test2<int>( 3.14 )是合法的constexpr通话。

现在,std::function没有没有这样的专业化,但这不是编译器需要证明的。这样做通常需要解决暂停问题,这是C ++标准试图避免要求编译器这样做的问题。

如@MaxLanghof所提到的,这种错误导致程序“格式错误,无需诊断”。不会强制编译器检测到您的constexpr函数不能为constexpr,但是如果这样做,编译器可以自由地执行任何操作,包括生成错误消息(或更糟的事情)。

因此,GCC忽略错误并没有错,而clang发出错误也没有错。从某种意义上说,Clang的错误发出要比gcc的遗漏要高。

答案 1 :(得分:2)

编辑:Yakk的答案更为完整-当然,必须考虑std::function专业化的理论可能性!

constexpr的意思是“至少有一组参数为此函数产生一个常量表达式”。如果不存在这样的参数,则程序格式错误,不需要诊断。这意味着由编译器决定是否完全忽略此问题,是否只在实例化时进行抱怨,或者是否已经声明了树皮。

clang显然是smart/eager enough,以意识到具有非文字返回类型的函数模板永远不会是constexprgcc似乎没有费心检查-并非必需。尽管您的程序仍然是错误的-std::function不是文字类型,因此永远无法从constexpr函数返回。