4
template<typename T,typename U = void>
struct Test
{
    static const int value = 0;
};
template<typename T>
struct Test<T, decltype((void)T{})>
{
    static const int value = 2;
};

template<typename T>
struct Test<T*,  decltype((void)T{})>
{
    static const int value = 1;
};

int main(){       
   cout<<Test<int*>::value<<endl;
    return 0;
}

code on gcc/clang both get error:ambiguous ,but decltype change to void_t is ok.why?

cpplearner
  • 13,776
  • 2
  • 47
  • 72
fe263
  • 121
  • 1
  • 7

1 Answers1

0

To me this looks like a compiler bug: do you really need side effects from T{}? The whole construct of decltype((void)T{}) should discard zero-initialized T, allowing unevaluated side-effects — so what's the point of such side effect, if there are any?
If you simplify it by just using void, or even omitting the whole second type, the problem goes away immediately (live demo on wandbox):

template<typename T, typename U = void>
struct Test
{
    static const int value = 0;
};
template<typename T>
struct Test<T, void>
{
    static const int value = 2;
};

template<typename T>
struct Test<T*, void>
{
    static const int value = 1;
};

int main(){       
    std::cout << Test<int*>::value << "\n";
    return 0;
}

Maybe there are some intricate details that I missed, but I tried many variants, including combinations of std::declval, std::result_of, alias templates, typedefs, none of which gave me anything meaningful.
But if we move the decltype((void)T{}) part out:

template<typename T>
using wrap = decltype((void)T{});

template<typename T>
struct Test<T, wrap<T>>
{
    static const int value = 2;
};
template<typename T>
struct Test<T*, wrap<T>>
{
    static const int value = 1;
};

GCC yells: ambiguous template instantiation for 'struct Test<int*, void>'. Which for me is a sign of something going in the wrong direction.

login_not_failed
  • 1,121
  • 2
  • 11
  • 19