gpt4 book ai didi

c++ - 可变参数模板的声明点

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:10:16 25 4
gpt4 key购买 nike

什么时候可变参数模板被认为是“声明的”?这会在 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...));
^

附录:如果我删除可变参数模板的声明,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());
}

最佳答案

作为this question's answer (由 Praetorian 提供)表明,只有返回类型后声明才完整,GCC 是正确的。我相信 clang 的行为也是允许的,但它不可移植。链接中的答案给出了使用 traits 类的解决方法,通常可以完成这项工作,但它有点笨拙并且容易出错(因为您必须在单独的表达式中构造返回类型,这可能与函数略有不同表达)。另一种可能的解决方法是使您的函数成为类模板的静态成员(然后添加一个转发到静态模板成员的自由函数)。

您可以考虑另一种解决方法,在您的第二个示例中暗示了该方法适用于两种编译器。当您在 A 上调用 sum() 时,您将应用用户定义的类型作为参数。这涉及参数依赖查找,这会导致模板生成在 A 的命名空间(恰好是全局命名空间,与 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++ - 可变参数模板的声明点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23002364/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com