即使未使用也会产生错误

即使未使用也会产生错误

本文介绍了模板成员函数具有尾部返回类型,即使未使用也会产生错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时删除!!

我理解模板成员函数只有在使用时才会生成。如果不是所有使用的类型都支持这样的功能,这是方便的。然而,这似乎不适用于具有尾部返回类型规范的函数。下面是一个小实验:

  $  $  
$ b

code>,具有适当的成员函数 f , g 。



但是,如果我尝试实例化 S< int> ,例如由 S< int> s {}; ,我会得到像类型的错误类型'int'不是一个结构或联合。这发生在尝试调用模板函数 f1 , g1 的两种情况 T (或非模板函数 g int )。即使我不是试图在对象 s上调用 f1 或 g1 code>。然而,GCC在 g1 的情况下很好; Clang不是。



案例A(模板成员函数 f )的解决方法是使用辅助函数 F ,这是 f2 的行为,并适用于Clang和GCC。它看起来工作,因为调用 T()。template f< A>()从 f2 ,并且当类型 A 未知时,编译器不在 F (T()) 。



对于情况B(非模板成员函数 g )的相同解决方法也适用于两个编译器。



我会感激一些帮助,找出发生了什么。在每种情况下都是正确的行为?哪个编译器是正确的?一般来说还有其他解决方法吗?



我使用GCC 4.8.1和Clang 3.3。

解决方案

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



T到第二个模板参数,但这只是您的解决方法的更短版本:

  #include< utility& 
#include< type_traits>
struct Foo {
template<类型名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必须等于T ;
return TT()。template f< A>();
}
};

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

S< int> b;
b.f1< int>(); // not ok
}


I understand that template member functions are only generated if used. This is convenient if not all used types support such a function. However, this does not appear to work for functions with trailing return type specification. Below is a small experiment:

// 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()); }
};

Please keep in mind that this sample is only meant to illustrate the issue, it is not useful in anything else.

S <T> can be instantiated for any type T that has appropriate member functions f, g.

However, if I try to instantiate S <int>, e.g. by S <int> s{};, I do get errors like type 'int' is not a structure or union. This happens for both cases f1, g1, which attempt to call template function f or non-template function g respectively on a value of type T (int in this case). It happens even though I am not trying to call f1 or g1 on object s. However, GCC is fine with the case of g1; Clang is not.

A workaround for case A (template member function f) is to use a helper function F, which is what f2 does, and works fine for both Clang and GCC. It appears to work because call T().template f <A>() is hidden from the declaration of f2, and the compiler is not looking into F <A>(T()) when type A is unknown.

The same workaround for case B (non-template member function g) is also working for both compilers.

I would appreciate some help in finding out what is going on. Which is the correct behaviour in each case? Which compiler is correct? Is there any other workaround in general?

I am using GCC 4.8.1 and Clang 3.3.

解决方案

SFINAE only applies to the template arguments of the function, not the one inherited from the class.

A different solution is to include copy T to a second template argument but this is nothing more than a shorter version of your workaround:

#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
}

这篇关于模板成员函数具有尾部返回类型,即使未使用也会产生错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

1403页,肝出来的..

09-06 09:15