【发布时间】:2017-03-30 02:39:45
【问题描述】:
考虑以下代码:
template<typename>
struct One {};
template<typename, typename>
struct Two {};
template<template<typename...> class TTP, typename...>
struct SS;
#ifdef TEST_TTP
template<template<typename> class OneParam,
typename... Ts>
struct SS<OneParam, Ts...> {};
template<template<typename, typename> class TwoParam,
typename... Ts>
struct SS<TwoParam, Ts...> {};
#else // TEST_TTP
template<template<typename> class OneParam,
typename TParam>
struct SS<OneParam, TParam> {};
template<template<typename, typename> class TwoParam,
typename TParam1,
typename TParam2>
struct SS<TwoParam, TParam1, TParam2> {};
#endif // TEST_TTP
int main() {
SS<One, int> ssoi;
SS<Two, int, int> sstii;
}
如果未定义 TEST_TTP,此代码将在 Clang、GCC 和 MSVC 上正确编译。但是,如果它被定义...
- 代码在 GCC 上正确编译,表明它识别出
OneParam和TwoParam与主模板中的TTP不同。 - Clang 无法识别
OneParam专门化TTP,导致它发出两个错误(第一个是部分专门化没有专门化任何模板参数,第二个是OneParam与之前的冲突-声明的模板模板参数)。然后它为TwoParam发出类似的错误(第一个是相同的,而第二个说模板模板参数有太多参数),并且SS的每个实例化都一个错误(因为它认为模板未定义) ,总共有 6 个错误。 - MSVC 发出与 Clang 类似的错误,但更简洁:它发出 C3855(
OneParam与主模板不兼容)和一个 C2079(变量使用未定义类型),用于SS的每个实例化,总共3 个错误。
现场演示on Coliru。
根据我的测试:
GCC 允许具有模板模板参数的模板仅根据模板模板参数采用的参数数量进行部分特化,该模板模板参数采用可变参数包。 Clang 和 MSVC 没有。
template<template<typename...> class T> struct S;
template<template<typename> class T> struct S<T> {}; // Only works with GCC.
template<template<typename, typename> class T> struct S<T> {}; // Only works with GCC.
但是,如果其他参数也专门化,Clang 和 MSVC 也可以。
template<template<typename...> class T, typename... Ts> struct S;
template<template<typename> class T,
typename TParam>
struct S<T, TParam> {};
template<template<typename, typename> class T,
typename TParam1,
typename TParam2>
struct S<T, TParam1, TParam2> {};
因此看起来前者不是合法的 C++,或者 Clang 和 MSVC 没有正确支持它。所以,问题是这样的:
考虑到这一点,根据模板模板参数采用的参数数量,对包含模板模板参数的模板进行部分特化的正确合法语法是什么?如果对此没有合法语法,是否支持它是 GCC 扩展和/或错误?
如果需要我执行的测试的完整记录以及提示此问题的原始示例,请查看编辑历史记录。
【问题讨论】:
标签: c++ visual-c++ g++ clang++ template-templates