我正在使用
decltype
来确保模板函数 force2
与另一个模板函数 force1
具有相同的参数和返回类型,但它无法编译。我需要将函数模板化。
考虑这段代码:
template <typename N>
void force1(N a);
template <typename N>
using ForceType = decltype(force1<N>);
template <typename N>
ForceType<N> force2;
template <typename N>
void force2(N a)
{}
这会导致错误:
<source>:11:16: error: 'template<class N> void force2(N)' conflicts with a previous declaration
11 | void force2(N a)
| ^
<source>:8:14: note: previous declaration 'template<class N> ForceType<N> force2<N>'
8 | ForceType<N> force2;
| ^~~~~~
Compiler returned: 1
我期望它能够编译:
force2
是一个空主体的模板化函数。这里到底发生了什么?编译器提示 template<class N> void force2(N)
与 template<class N> ForceType<N> force2<N>
不同,我无法理解。乍一看它们确实不同,但 ForceType<N>
的扩展不应该导致 template<class N> void force2(N)
吗?
当我在
force2
的声明中使用具体类型时:
template <typename N>
void force1(N a);
template <typename N>
using ForceType = decltype(force1<N>);
ForceType<int> force2;
void force2(int a)
{}
编译没有错误。
ForceType<N>
是依赖类型。
如果函数声明通过依赖类型获取其函数类型而不使用函数声明符的语法形式,则该程序是格式错误的。
ForceType<N> force2;
不满足此要求,因此格式不正确。
在编译器中,这将被解析为变量模板,因为由于上述规则,它不能是函数模板。
任何实际使用
force2<N>
的尝试都会导致错误(https://godbolt.org/z/f3Ke3x8db)
即使你要通过函数声明的形式来修复它:
template<typename>
struct unary_fn;
template<typename Ret, typename Arg>
struct unary_fn<Ret(Arg)> { using return_type = Ret; using argument_type = Arg; };
template <typename N>
void force1(N a);
template <typename N>
using ForceType = typename unary_fn<decltype(force1<N>)>::return_type(typename unary_fn<decltype(force1<N>)>::argument_type);
template <typename N>
ForceType<N> force2;
template <typename N>
void force2(N a)
{}
这将声明两个单独的模板重载,因为
ForceType<N>
和 void(N)
不等价(即,后者不是前者的定义)
在
using ForceType
模板声明中,decltype(force1<N>)
是 void(N a)
。所以 ForceType<int> force2;
与声明 void force2(int a)
是一样的,它只是一个函数,而不是函数模板。
现在,在
template <typename N> void force2(N a) {}
中,您尝试声明一个名为 force2
的模板,该模板已被之前的声明“使用”。
注意,在第二个示例中,
void force2(int a) {}
是函数的定义,与force2
声明不冲突。