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

member function implementation depending on template parameter

本文关键字:参数 取决于 实现 函数 成员      更新时间:2023-10-16

我有以下问题:

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)和sizeof...(N_i)+1 -许多size_t

根据传递的size_t(即sizeof...(N_i)+1)的数量,我将使用具有不同结果类型的成员函数operator[](size_t)的不同实现:

  • sizeof...(N_i)+1 > 1的一个实现,返回类型A < T, N_i... >(在代码中称为"第一次实现")
  • 和一个用于返回类型为T的case sizeof...(N_i)+1 == 1(在代码中称为"第二次实现")。

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

提前感谢。

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;
}
演示

如果修改

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

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

return ... ;

return T{} ;

还不够吗?

—EDIT—

不:正如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;
 }

如果你不想对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;
 }