繁体   English   中英

可变参数模板的声明点

[英]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...));
                                                                      ^

附录:如果我删除可变参数模板的声明,则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类的解决方法,通常可以完成该工作,但是它有些笨拙,并且容易出错(因为您必须在单独的表达式中构造return类型,这可能与函数有细微的区别)表达)。 另一个可能的解决方法是使函数成为类模板的静态成员(然后添加转发到静态模板成员的自由函数)。

您可以考虑另一种解决方法,这在第二个示例中都得到了提示,该示例在两个编译器上均有效。 A上调用sum()时,您将应用用户定义的类型作为参数。 这涉及依赖于参数的查找,这导致模板生成第二次查找A的名称空间(恰好是全局名称空间,与sum()相同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;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM