模板成员函数具有尾随返回类型,即使未使用也会出错

iav*_*avr 6 c++ templates member-functions c++11 trailing-return-type

我知道模板成员函数只有在使用时才会生成.如果不是所有使用的类型都支持这样的功能,这很方便.但是,这似乎不适用于具有尾随返回类型规范的函数.以下是一个小实验:

// helper function for case A workaround
template <typename A, typename T>
auto F(T&& x)
-> decltype(x.template f <A>())
    { return x.template f <A>(); }

// helper function for case B workaround
template <typename A, typename T>
auto G(T&& x)
-> decltype(x.g())
    { return x.g(); }

template <typename T>
struct S
{
    // case A: not ok in GCC + Clang
    template <typename A>
    auto f1()
    -> decltype(T().template f <A>())
        { return T().template f <A>(); }

    // case A workaround: ok in Clang + GCC
    template <typename A>
    auto f2()
    -> decltype(F <A>(T()))
        { return F <A>(T()); }

    // case B: ok in GCC, not ok in Clang
    template <typename A>
    auto g1()
    -> decltype(T().g())
        { return T().g(); }

    // case B workaround: ok in GCC + Clang
    template <typename A>
    auto g2()
    -> decltype(G <A>(T()))
        { return G <A>(T()); }
};
Run Code Online (Sandbox Code Playgroud)

请记住,此示例仅用于说明问题,在其他任何方面都没有用.

S <T>可以被实例化的任何类型的T,其具有适当的成员函数f,g.

但是,如果我尝试实例化S <int>,例如S <int> s{};,我确实会遇到错误type 'int' is not a structure or union.发生这种情况的两种情况下f1,g1,其试图调用模板函数f或非模板函数g分别类型的值T(int在这种情况下).这是即使我不是想打电话f1g1上对象s.但是,海湾合作委员会的情况很好g1; Clang不是.

案例A(模板成员函数f)的解决方法是使用辅助函数F,这是什么f2,并且对Clang和GCC都可以正常工作.它似乎有效,因为调用T().template f <A>()在声明中是隐藏的f2,编译器F <A>(T())在类型A未知时不会查看.

案例B(非模板成员函数g)的相同解决方法也适用于两个编译器.

我希望得到一些帮助,找出发生了什么.在每种情况下哪种行为是正确的?哪个编译器正确?一般还有其他解决方法吗?

我正在使用GCC 4.8.1和Clang 3.3.

gal*_*p1n 1

SFINAE 仅适用于函数的模板参数,而不适用于从类继承的模板参数。

一种不同的解决方案是将 copy T 包含到第二个模板参数中,但这只不过是解决方法的较短版本:

#include <utility>
#include <type_traits>    
struct Foo {
    template < typename T > T f() { return {}; }
};
template <typename T>
struct S {
    template <typename A, typename TT = T >
    auto f1()  -> decltype(std::declval<TT>().template f <A>()) { 
        static_assert(std::is_same<T,TT>::value, "TT must be equal to T" );
        return TT().template f <A>(); 
    }
};

int main() {
    S<Foo> a;
    a.f1<int>(); // ok

    S<int> b;
    b.f1<int>(); // not ok
}
Run Code Online (Sandbox Code Playgroud)