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.