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;
}
gcc / clang上的代码都得到错误:模棱两可,但是将decltype更改为void_t没问题。为什么?
答案 0 :(得分:0)
对我来说,这看起来像是编译器错误:您真的需要T{}
的副作用吗? decltype((void)T{})
的整个构造都应该丢弃零初始化的T
,从而产生未评估的副作用-那么,如果有副作用,那么这又意味着什么呢?
如果仅使用void
甚至简化第二种类型就可以简化问题,那么问题就会立即消失(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;
}
也许我错过了一些复杂的细节,但是我尝试了许多变体,包括std::declval
,std::result_of
,别名模板,typedef的组合,这些都没有给我带来任何意义。
但是如果我们将decltype((void)T{})
部分移出:
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大喊:ambiguous template instantiation for 'struct Test<int*, void>'
。对我来说,这标志着事情朝着错误的方向前进。