Alias templates used in SFINAE lead to a hard error

痴心易碎 提交于 2019-12-02 06:42:38

问题


I want to use an enabler (an alias template of enable_if), defined in one class template, in another class template. It looks like this:

template< ... > using enabler = typename std::enable_if< ... >::type;

This works fine for SFINAE. But when I add another alias template in the second class like

template< ... > using enabler
    = typename first_class<..> :: template enabler< ... >;

and use this enabler for SFINAE, substitution (correctly) fails but with a hard error for g++4.8.0 and 4.8.1. clang++3.4 gives only a soft error and SFINAE works.

#include <iostream>
#include <type_traits>

#include <cstdlib>

template< typename T >
class A
{

    struct B {};

public :

    struct U : B {};

    template< typename D, typename R = void >
    using enable_if_is_B = typename std::enable_if< std::is_base_of< B, D >::value, R >::type;

    template< typename D, typename R = void >
    using enable_if_is_not_B = typename std::enable_if< !std::is_base_of< B, D >::value, R >::type;

    template< typename D >
    auto
    operator () (D const &) const
    -> enable_if_is_B< D >
    {
        std::cout << "D is B" << std::endl;
    }

    template< typename D >
    auto
    operator () (D const &) const
    -> enable_if_is_not_B< D >
    {
        std::cout << "D is not B" << std::endl;
    }

};

template< typename T >
struct B
{

    using A_type = A< T >;

    template< typename D, typename R = void >
    using enable_if_is_B = typename A_type::template enable_if_is_B< D, R >;

    template< typename D, typename R = void >
    using enable_if_is_not_B = typename A_type::template enable_if_is_not_B< D, R >;

    template< typename D >
    auto
    operator () (D const &) const
    -> enable_if_is_B< D >
    {
        std::cout << "D is B!" << std::endl;
    }

    template< typename D >
    auto
    operator () (D const &) const
    -> enable_if_is_not_B< D >
    {
        std::cout << "D is not B!" << std::endl;
    }

};

int main()
{
    using T = struct Z;
    using A_type = A< T >;
    using U = typename A_type::U;
#if 0
    using X = A< T >;
#else
    using X = B< T >;
#endif
    X const x;
    x(0);
    x(U());
    return EXIT_SUCCESS;
}

Which with #if 1 produces:

D is not B
D is B

But for using X = B< T >; generates an error on g+4.8.0:

<stdin>: In substitution of 'template<class T> template<class D, class R> using enable_if_is_B = typename std::enable_if<std::is_base_of<A<T>::B, D>::value, R>::type [with D = int; R = void; T = main()::Z]':
<stdin>:48:73:   required by substitution of 'template<class T> template<class D, class R> using enable_if_is_B = typename B<T>::A_type::enable_if_is_B<D, R> [with D = int; R = void; T = main()::Z]'
<stdin>:55:2:   required by substitution of 'template<class D> B<T>::enable_if_is_B<D> B<T>::operator()(const D&) const [with D = D; T = main()::Z] [with D = int]'
<stdin>:82:5:   required from here
<stdin>:18:91: error: no type named 'type' in 'struct std::enable_if<false, void>'
<stdin>: In substitution of 'template<class T> template<class D, class R> using enable_if_is_not_B = typename std::enable_if<(! std::is_base_of<A<T>::B, D>::value), R>::type [with D = A<main()::Z>::U; R = void; T = main()::Z]':
<stdin>:51:81:   required by substitution of 'template<class T> template<class D, class R> using enable_if_is_not_B = typename B<T>::A_type::enable_if_is_not_B<D, R> [with D = A<main()::Z>::U; R = void; T = main()::Z]'
<stdin>:63:2:   required by substitution of 'template<class D> B<T>::enable_if_is_not_B<D> B<T>::operator()(const D&) const [with D = D; T = main()::Z] [with D = A<main()::Z>::U]'
<stdin>:83:7:   required from here
<stdin>:21:96: error: no type named 'type' in 'struct std::enable_if<false, void>'

How to "export/import" the enabler from one class template to another?

Why SFINAE does not work?

来源:https://stackoverflow.com/questions/19378749/alias-templates-used-in-sfinae-lead-to-a-hard-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!