非类型的模板专业化

时间:2018-03-30 14:39:29

标签: c++ templates template-meta-programming template-specialization

考虑到我有一个简单的类模板:

template <typename T>
class foo
{
    T t;
};

是否可以专门化foo,使T不是类型而是非类型值,以便:

foo<float> my_foo;

使用上面显示的类模板,而

foo<20> my_other_foo;

使用不同的模板专业化?这是可能的,如果是的话,模板专业化代码会是什么样的?

2 个答案:

答案 0 :(得分:1)

  

这是可能的,如果是的话,部分专业化代码会是什么样的?

正如你想要的那样,不,这是不可能的。

但是,如果你可以使用C ++ 17,你可以做出几乎相反的事情:收到auto值(T成为值的declval()

template <auto Val>
struct foo
 {
   using T = decltype(Val);

   T t { Val }; // or also decltype(Val) t {Val};

   static constexpr bool isSpecialized { false };
 };

您可以专注于20(其中20int;不符合(例如)20L20U

template <>
struct foo<20>
 {
   static constexpr bool isSpecialized { true };
 };

此解决方案的问题在于您不能拥有foo<float>,因为float值不能是模板非类型参数(因此您无法编写foo<0.0f> ,例如)。

您可以粗略地绕过此问题,添加第二个模板类型参数,其中包含默认值(第一个参数的类型)

template <auto Val, typename T = decltype(Val)>
struct bar
 {
   T t { Val };

   static constexpr bool isSpecialized { false };
 };

并且20专业化仍然存在

template <>
struct bar<20>
 {
   static constexpr bool isSpecialized { true };
 };

但现在您可以拨打bar<0, float>来代替旧foo<float>

以下是完整的编译(显然是C ++ 17)示例

#include <iostream>

template <auto Val>
struct foo
 {
   using T = decltype(Val);

   T t { Val }; // or also decltype(Val) t {Val};

   static constexpr bool isSpecialized { false };
 };

template <>
struct foo<20>
 {
   static constexpr bool isSpecialized { true };
 };

template <auto Val, typename T = decltype(Val)>
struct bar
 {
   T t { Val };

   static constexpr bool isSpecialized { false };
 };

template <>
struct bar<20>
 {
   static constexpr bool isSpecialized { true };
 };

int main ()
 {
   std::cout << foo<0>::isSpecialized << std::endl;   // print 0
   std::cout << foo<20>::isSpecialized << std::endl;  // print 1
   std::cout << foo<20L>::isSpecialized << std::endl; // print 0

   std::cout << bar<0>::isSpecialized << std::endl;         // print 0
   std::cout << bar<20>::isSpecialized << std::endl;        // print 1
   std::cout << bar<20L>::isSpecialized << std::endl;       // print 0
   std::cout << bar<20, float>::isSpecialized << std::endl; // print 0

 }

答案 1 :(得分:0)

#include <type_traits>
#include <iostream>

template <typename T>
struct foo
{
    foo(T x) : t(x) {};

    T t;
};

// specialise for integral constant
template<class T, T N>
struct foo<std::integral_constant<T, N>>
{
    // same interface
    static constexpr T t = N;
};

// test
int main()
{
    auto foo1 = foo<float>(10.0);
    auto foo2 = foo<std::integral_constant<int, 20>>();

    std::cout << foo1.t << std::endl;
    std::cout << foo2.t << std::endl;
}