不能推导模板Partial Specialization中的decltype((void)T {})?

时间:2018-06-30 00:54:03

标签: c++ c++11 c++14 partial-specialization

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没问题。为什么?

1 个答案:

答案 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::declvalstd::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>'。对我来说,这标志着事情朝着错误的方向前进。