3

我正在尝试创建一个函数,该函数返回数组数组的零填充数组...在我定义的现代 C++ 中优雅地定义多维数组之后

template<typename U, std::size_t N, std::size_t... M>                                                                                                                                                               
struct myTensor{                                                                                                                                                                                                    
  using type = std::array<typename myTensor<U, M...>::type, N>;                                                                                                                                                     
};                                                                                                                                                                                                                  
template<typename U, std::size_t N>                                                                                                                                                                                 
struct myTensor<U,N>{                                                                                                                                                                                               
  using type = std::array<U, N>;                                                                                                                                                                                    
};                                                                                                                                                                                                                  
template<typename U, std::size_t... N>                                                                                                                                                                              
using myTensor_t = typename myTensor<U, N...>::type;

然后我定义以下模板函数来填充零:

template<typename U, std::size_t N, std::size_t... M>                                                                                                                                                               
myTensor_t<U, N, M...> Zero_Tensor(){                                                                                                                                                                               
  myTensor_t<U, N, M...> res;                                                                                                                                                                                       
  for(int i=0; i<N; i++)                                                                                                                                                                                            
    res[i] = Zero_Tensor<U, M...>();                                                                                                                                                                                
  return res;                                                                                                                                                                                                       
};                                                                                                                                                                                                                  
                                                                                                                                                                                                                    
template<typename U, std::size_t N>                                                                                                                                                                                 
myTensor_t<U, N> Zero_Tensor(){                                                                                                                                                                                     
  myTensor_t<U, N> res;                                                                                                                                                                                             
  for(int i=0; i<N; i++)                                                                                                                                                                                            
    res[i] = U(0);                                                                                                                                                                                                  
  return res;                                                                                                                                                                                                       
};

例如,当我这样做时

class myclass{
myTensor_t<int,3,3,5> x;
};

它编译得很好。如果我尝试这样做:

class myclass{
myTensor_t<int,3,3,5> x=Zero_Tensor<int,3,3,5>();
};

我在编译时收到以下错误:

src/mytensor.hpp(107): error: no instance of overloaded function "Zero_Tensor" matches the argument list
      res[i] = Zero_Tensor<U, M...>();
               ^
src/mytensor.hpp(112): note: this candidate was rejected because function is not visible
  myTensor_t<U, N> Zero_Tensor(){
                   ^
src/mytensor.hpp(104): note: this candidate was rejected because at least one template argument could not be deduced
  myTensor_t<U, N, M...> Zero_Tensor(){
                         ^
          detected during:
            instantiation of "myTensor_t<U, N, M...> Zero_Tensor<U,N,M...>() [with U=int, N=5UL, M=<>]" at line 107
            instantiation of "myTensor_t<U, N, M...> Zero_Tensor<U,N,M...>() [with U=int, N=3UL, M=<5UL>]" at line 107
            instantiation of "myTensor_t<U, N, M...> Zero_Tensor<U,N,M...>() [with U=int, N=3UL, M=<3UL, 5UL>]" at line 36 of "src/myclass.hpp"

我真的不明白this candidate was rejected because function is not visible在告诉我什么。我想我不明白为什么它不可见?任何帮助表示赞赏。

4

2 回答 2

2

建议:重写你的Zero_Tensor()功能如下

template <typename U>
U Zero_Tensor () 
 { return U(0); }

template <typename U, std::size_t N, std::size_t... M>
myTensor_t<U, N, M...> Zero_Tensor ()
 {
   myTensor_t<U, N, M...> res;

   for ( auto i = 0u ; i < N ; ++i )
      res[i] = Zero_Tensor<U, M...>();

   return res;
 }

现在你的问题是底层版本(递归结束,<U, N>版本)是在递归版本(the )之后<U, N, M...>定义的,所以当递归版本调用

 Zero_Tensor<U, M...>();

并且M...包是空的,编译器不知道一个Zero_Tensor()只接受一个U类型作为模板参数的函数。

您可以颠倒定义的顺序(或在递归案例之前声明基本案例)但您还有另一个问题:当您调用

 Zero_Tensor<U, M...>();

并且M...包仅包含一个数字,您的呼叫不明确,因为两个版本都匹配。

解决方案:使用更简单的接地案例

template <typename U>
U Zero_Tensor () 
 { return U(0); }

并在递归案例之前定义它。

这种方式

 Zero_Tensor<U, M...>();

永远不会模棱两可,因为当M...包为空时,只有基本情况匹配,否则只有递归情况匹配。

离题建议:当您有一个从零到无符号数的循环时(如您的示例)

// ............V  N is std::size_t, an unsigned type
for(int i=0; i<N; i++)

使用无符号变量作为索引变量i

于 2020-06-22T20:57:22.343 回答
2

问题是,当您实例化为空时,(只有 2 个模板参数)的另一个重载Zero_Tensor是不可见的。如果您在参数包版本之前移动该重载,您将遇到在传入 2 个模板参数时重载不明确的问题。M...Zero_Tensor

您可以通过仅使用一个Zero_Tensor函数来解决此问题,该函数根据 的大小决定要做什么M...,如下所示:

template<typename U, std::size_t N, std::size_t... M>                                                                                                                                                               
myTensor_t<U, N, M...> Zero_Tensor(){                                                                                                                                                                               
  myTensor_t<U, N, M...> res;                                                                                                                                                                                       
  for(int i=0; i<N; i++)                                                                                                                                                                                            
    if constexpr(sizeof...(M) > 0)
      res[i] = Zero_Tensor<U, M...>();                                                                                                                                                                                
    else 
      res[i] = U(0);     
  return res;                                                                                                                                                                                                       
};                                                                                                                                                                                                                  

这是一个演示。请注意,这需要 c++17。

于 2020-06-22T21:09:45.190 回答