变量模板的声明点
Point of declaration for variadic template
变量模板在什么时候被视为"已声明"?这是在clang++3.4下编译的,但不是在g++4.8.2下编译的。
template <typename T>
const T &sum(const T &v) { return v; }
template <typename T, typename ... Ts>
auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...));
template <typename T, typename ... Ts>
auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...)) {
return v + sum(params...);
}
int main() {
sum(1, 2, 3);
}
显然g++在后面的返回类型中与函数本身不匹配。g++4.8.2的错误为:
sum.cpp: In function 'int main()':
sum.cpp:13:16: error: no matching function for call to 'sum(int, int, int)'
sum(1, 2, 3);
^
sum.cpp:13:16: note: candidates are:
sum.cpp:2:10: note: template<class T> const T& sum(const T&)
const T &sum(const T &v) { return v; }
^
sum.cpp:2:10: note: template argument deduction/substitution failed:
sum.cpp:13:16: note: candidate expects 1 argument, 3 provided
sum(1, 2, 3);
^
sum.cpp:8:6: note: template<class T, class ... Ts> decltype ((v + sum(sum::params ...))) sum(const T&, const Ts& ...)
auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...)) {
^
sum.cpp:8:6: note: template argument deduction/substitution failed:
sum.cpp: In substitution of 'template<class T, class ... Ts> decltype ((v + sum(sum::params ...))) sum(const T&, const Ts& ...) [with T = int; Ts = {int, int}]':
sum.cpp:13:16: required from here
sum.cpp:5:74: error: no matching function for call to 'sum(const int&, const int&)'
auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...));
^
sum.cpp:5:74: note: candidate is:
sum.cpp:2:10: note: template<class T> const T& sum(const T&)
const T &sum(const T &v) { return v; }
^
sum.cpp:2:10: note: template argument deduction/substitution failed:
sum.cpp:5:74: note: candidate expects 1 argument, 2 provided
auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...));
^
附录:如果我删除varadic模板的声明,clang++和g++都会出现错误。
附录2:我看到以前也有人问过类似的问题。我想这里真正的问题是为什么它能用一个编译器而不能用另一个编译器。此外,我可以通过使用sum()的非基元参数在POI处强制ADL,使其与g++一起工作。
附录3:这在clang++和g++下都有效:
class A {
};
A operator+(const A &, const A &) {
return A();
}
template <typename T>
const T &sum(const T &v) { return v; }
/*
template <typename T, typename ... Ts>
auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...));
*/
template <typename T, typename ... Ts>
auto sum(const T &v, const Ts & ... params) -> decltype(v + sum(params...)) {
return v + sum(params...);
}
int main() {
//sum(1, 2, 3);
sum(A(), A(), A());
}
正如这个问题的答案(由Praetorian提供)所示,只有在返回类型之后声明才是完整的,GCC是正确的。我相信clang的行为也是可以允许的,但它是不可移植的。链接中的答案提供了一个使用traits类的解决方法,这通常可以完成任务,但这有点尴尬,而且可能容易出错(因为你必须在一个单独的表达式中构造返回类型,这个表达式可能与函数表达式有细微的不同)。另一种可能的解决方法是使函数成为类模板的静态成员(然后添加一个转发给静态模板成员的自由函数)。
您可以考虑另一种变通方法,这在第二个示例中有所暗示,该示例适用于两个编译器。当您在A
上调用sum()
时,您正在将用户定义的类型应用为参数。这涉及到依赖于参数的查找,这导致模板生成在A
的命名空间(恰好是全局命名空间,与sum()
相同)中第二次查找sum()
的重载,并且这允许它在实例化期间找到可变函数模板。
因此,如果你可以安排你的一个参数始终是一个需要ADL的用户定义类型,那么你就可以在重载解析的第二阶段找到变量模板。所以,也许这样的东西可以满足你的需求:
namespace sum_impl {
struct Dummy { };
template <typename T>
T const &sum_helper(Dummy, T const &v) { return v; }
template <typename T, typename ... Ts>
auto sum_helper(Dummy d, T const &v, Ts const &...params)
-> decltype(v + sum_helper(d, params...)) {
return v + sum_helper(d, params...);
}
template<typename... P>
auto sum( P const &...p )
-> decltype( sum_helper( Dummy{}, p... ) {
return sum_helper( Dummy{}, p... );
}
}
using sum_impl::sum;
- 在疯狂的部分中声明变量
- 如何在C++中为高分辨率时钟声明变量?
- 在命名空间中声明变量,在 main 中定义它,使其对所有其他文件可见
- CUDA 的性能取决于声明变量
- 如何在不为其声明变量的情况下获取和使用常量值的地址?
- C++声明变量时自动类型推断而不初始化
- 在不同循环中多次声明变量的优点
- 奇怪的错误 C2131 与 constexpr 声明变量
- 是否可以在 "if" 语句中声明变量?
- 在python-ctypes中声明变量并传递给dll函数
- 在递归函数C++中声明变量
- 只有一个定义/声明时标头声明变量的多堆定义错误
- 奇怪的未声明变量编译器错误
- 我在C++程序中声明变量时遇到问题
- 在命名空间中声明变量
- C++ lambda 按值捕获,而无需更早声明变量
- 声明变量以保存字符串列表时的内存分配
- 如何声明C 变量应突变
- 为什么允许在开关语句中声明变量?但不是声明 初始化
- 在同一命名空间中声明变量和函数是否出错?[C++]