使用来自外部 class 的可变参数模板的参数部分特化可变参数模板内部 class 是否合法

Is it legal to partially specialise variadic template inner class with args from variadic template of an outer class

考虑代码:

#include <iostream>

template <class... Ts>
struct outer {
   template <class... ITs>
   struct inner {
      static constexpr bool value = false;
   };

   template <class... ITs>
   struct inner<Ts..., ITs...> {   
      static constexpr bool value = true;
   };
};

int main() {
   std::cout << outer<int, float, double>::inner<int, float, double, int>::value << std::endl;
}

代码使用 clang++ 编译,但不使用 g++ 编译,它会产生错误:

temp3.cc:11:11: error: parameter pack argument ‘Ts ...’ must be at the end of the template argument list

struct inner<Ts..., ITs...> {
       ^

正如我已经建立的 内部 class 的部分专业化应该是合法的。

编辑: 为了完整起见,值得补充的是,上述代码的 clang 警告他可能在推导 IT 参数时遇到问题但没有任何问题...

这是一个 gcc 错误。这是一个完全有效的偏特化:

template <class... ITs>
struct inner<Ts..., ITs...> {   
   static constexpr bool value = true;
};

推导的模板参数包必须在最后,ITs...满足。但是Ts...并不是这里需要推导的包,它只是一个特定的参数包。

此外,gcc 编译了几个等效的公式:

template <class... Ts>
struct X {
    template <class... Us>
    static void foo(Ts..., Us...) { }
};

int main() {
   X<int>::foo(1, 'c');
}

和:

template <class... Us>
struct A { };

template <class... Ts>
struct X {
    template <class... Us>
    static void foo(A<Ts..., Us...>) { }
};

int main() {
   X<int>::foo(A<int, char>{});
}

这些与您的原始示例等效。

受 Barry 回答启发的可能的简单而有效的解决方法:

#include <iostream>

template <class... Ts>
struct pack { };

template <class... Ts>
struct outer {
   template <class IT>
   struct inner {
      static constexpr bool value = false;
   };

   template <class... ITs>
   struct inner<pack<Ts..., ITs...>> {   
      static constexpr bool value = true;
   };
};

int main() {
   std::cout << outer<int, float, double>::inner<pack<int, float, double, int>>::value << std::endl;
}

(虽然它仍然在 clang 中产生警告)

基于 W.F. 的回答,仍然保持与原始问题相同的主要内容:

#include <iostream>

template <class... Ts>
struct pack { };

template <class... Ts>
class outer {
   template <class IT>
   struct _inner {
      static constexpr bool value = false;
   };

   template <class... ITs>
   struct _inner<pack<Ts..., ITs...>> {
      static constexpr bool value = true;
   };
public:
   template <class... ITs>
   struct inner {
      static constexpr bool value = _inner<pack<ITs...>>::value;
   };    
};

int main() {
   std::cout << outer<int, float, double>::inner<int, float, double, int>::value
             << std::endl;
}

它仍然在 clang 中产生警告,因为 _inner 的专用版本无法推断出 ITs... 除了 Ts...,ITs... 的列表(在 struct _inner<pack<Ts..., ITs...>> 中)- - 但是代码不需要从 Ts...,ITs... 列表中单独推导出 ITs,所以这应该没问题。

在 g++ 中编译时没有警告。

代码:http://coliru.stacked-crooked.com/a/ae3b21dd847450b2

(对于在 clang 中也没有警告的解决方案:http://coliru.stacked-crooked.com/a/0c6c643c8ff5809e)。