成员函数实现取决于模板参数

时间:2016-10-13 15:32:35

标签: c++ c++11 templates variadic-templates sfinae

我有以下问题:

template< typename T, size_t N, size_t... N_i >
class A
{  
  public:

    // ...

    // first implementation
    template< size_t M = sizeof...(N_i)+1, typename std::enable_if< M!=1, size_t >::type = 0 >
    A<T, N_i...> operator[]( size_t i )
    {
      A< T, N_i... > res{ ... };

      return res;
    }

    // second implementation
    template< size_t M = sizeof...(N_i)+1, typename std::enable_if< M==1, size_t >::type = 0 >
    T operator[]( size_t i )
    {
      return ... ;
    }
};

正如您在上面所看到的,我尝试实现一个类A,它希望模板参数为T类型(例如intfloat)和{{1很多sizeof...(N_i)+1

取决于传递的size_t(即size_t)的数量,我将对成员函数sizeof...(N_i)+1使用不同的实现,结果类型不同:

  • 案例operator[](size_t)的一个实现,返回类型为sizeof...(N_i)+1 > 1 (在代码中称为“第一个实现”)
  • 和一个案例A < T, N_i... >,返回类型为sizeof...(N_i)+1 == 1 (在代码中称为“第二个实现”)。

不幸的是,我不知道如何实现这一点 - 上面的解决方案不起作用。有人有想法吗?

非常感谢提前。

2 个答案:

答案 0 :(得分:2)

如果修改

A< T, N_i... > res{ ... };

A< T, N_i... > res{ };

return ... ;

return T{} ;

还不够?

---编辑---

否:正如Jarod42指出的那样(谢谢!),还不够。

所以我提出了以下解决方案,基于类模板特化和std::conditional以避免使用SFINAE

#include <iostream>
#include <type_traits>

template< typename, size_t...>
class A;

template< typename T, size_t N, size_t... N_i >
class A<T, N, N_i...>
 {  
   public:
      template <typename Next = typename std::conditional<sizeof...(N_i),
                                           A<T, N_i...>, T>::type>
      Next operator[] (size_t i)
       { return Next{}; }
 };

int main(int argc, char* argv[]) 
 {
   A<int, 2, 4> a;

   std::cout << a[1][2] << std::endl;

   return 0;
 }

如果您不想使用specialize A,则可以添加A的子结构来执行脏工作。

#include <iostream>
#include <type_traits>

template< typename T, size_t N, size_t... N_i >
class A
 {  
   template <typename U, size_t ... O_i>
      struct Next
       { using type = A<U, O_i...>; };

   template <typename U>
      struct Next<U>
       { using type = U; };

   public:
      using next_t = typename Next<T, N_i...>::type;

      next_t operator[] (size_t i)
       { return next_t{}; }
 };

int main(int argc, char* argv[]) 
 {
   A<int, 2, 4> a;

   std::cout << a[1][2] << std::endl;

   return 0;
 }

答案 1 :(得分:2)

A<T, N_i...>对空N_i无效。 作为解决方法,您可以使用间接:

template <typename, std::size_t ...>
struct PopFrontA
{
    using type = void; // Dummy type for A<T, N>
};

template< typename T, std::size_t N, std::size_t... N_i > class A;

template <typename T, std::size_t N, std::size_t N2, std::size_t ... Ns>
struct PopFrontA<T, N, N2, Ns...>
{
    using type = A<T, N2, Ns...>;
};

template <typename T, std::size_t ... Ns>
using PopFrontA_t = typename PopFrontA<T, Ns...>::type;

然后

// first implementation
template< size_t M = sizeof...(N_i)+1, typename std::enable_if< M!=1, size_t >::type = 0 >
PopFrontA_t<T, N, N_i...>
operator[]( size_t i )
{
  A< T, N_i... > res{ /*...*/ };

  return res;
}

Demo