STD ::功能,字面类型和模板

std::function, literal types and templates

本文关键字:类型 功能 STD      更新时间:2023-10-16

我正在从事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,但第二起正常工作。

为什么会发生这种情况?这与第二个功能的返回类型是模板有关吗?

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

有趣的是,在线gdb和Offline GCC 8.3.0并没有抱怨,但是我的clang 8会。

令我惊讶的是,第一个声明原因是编译器错误constexpr函数的返回类型不是字面类型,但第二起工作正好。

为什么会发生这种情况?这与第二个功能的返回类型是模板有关吗?

是。在第一种情况下,编译器可以证明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 {}; }

实例示例

test是非法的;test2很好。实际上,test2<int>( 3.14 )是法律constexpr调用。

现在,std::function具有没有这样的专业化,但这不是编译器证明的要求;一般而言,这样做需要解决停止问题,这是C 标准试图避免要求编译器做的事情。

正如@maxlanghof所述,这种错误导致"不良形式,无需诊断"。程序。编译器不会被迫检测到您的constexpr函数不能为constexpr,但是如果您执行编译器可以免费执行任何操作,包括生成错误消息(或更糟糕的消息(。

因此,GCC省略错误并不是错误的,并且发出错误并没有错。从某种意义上说,Clang的误差排放比GCC的遗漏更高。

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

constexpr的意思是"至少有一组参数会产生恒定表达式"。如果没有这样的论点,则该程序是不形式的,无需诊断。这意味着是否完全忽略了此问题,无论它仅在实例化时还是已经在声明中吠叫。

clang显然很聪明/渴望,足以意识到具有非文字返回类型的功能模板永远不可能是constexprgcc似乎并没有打扰检查此问题 - 不需要。但是您的程序仍然错了-std::function不是字面类型,因此永远不能从constexpr函数中返回。