1

目前我有一个模板函数,编译器可以推断出TI静态数组和指针(常见类型)作为参数:

template<typename TI, typename TO>
inline void foo(const TI a[4], TO b[][3]) { /* works for static arrays and pointers */ }

但是,现在我需要对具有 4 个成员x、和的结构类型具有相同的功能y,它们表示旧数组类型上的相同 4 个项目。zw

但我不能这样做:

template<typename TI, typename TO>
inline void foo(const TI a[4], TO b[][3]) { /* static arrays and pointer */ }


template<typename TI, typename TO>
inline void foo(const TI a, TO b[][3]) { /* structs */ }

如果我为第一个函数指定一个额外的参数size,那么指针参数最终会出现在下面的函数上,并且编译器会引发错误,因为指针没有所需的结构成员。

我不能专门针对特定类型的结构,因为我们现在使用多种类型(不同的内部成员类型的double, float,int等)


MRE:

#include <cassert>
#include <iostream>
 
template <typename TI, typename TO>
inline
void foo(const TI q[4], TO a[][3])
{
    std::cout << "Method 1\n";
    a[0][0] = a[0][1] = a[0][2] = q[0] + q[1];
    a[1][0] = a[1][1] = a[1][2] = q[1] + q[2];
    a[2][0] = a[2][1] = a[2][2] = q[2] + q[3];
}
 
template <class QT, typename TO>
inline
void foo(const QT q, TO a[][3])
{
    std::cout << "Method 2\n";
    a[0][0] = a[0][1] = a[0][2] = q.x + q.y;
    a[1][0] = a[1][1] = a[1][2] = q.y + q.z;
    a[2][0] = a[2][1] = a[2][2] = q.z + q.w;
}
 
typedef struct {
    float x, y, z, w;
} float4;
 
int main() {
 
    float q1[4] = {1, 2, 3, 4};
    float4 q2 = {1, 2, 3, 4};
    float *q3 = new float[4];
    q3[0] = 1; q3[1] = 2; q3[2] = 3; q3[3] = 4;
    
    float a[3][3], b[3][3], c[3][3];
    
    foo(q1, a);
    foo(q2, b);
    foo(q3, c);
    
    for (int i = 0; i < 3; i++)
            for (int j = 0; j < 3; j++)
            {
                assert(a[i][j] == b[i][j]);
                assert(b[i][j] == c[i][j]);
            }
}

编译器错误:

teste.cpp:19:36: error: member reference base type 'float *const' is not a structure or
      union
    a[0][0] = a[0][1] = a[0][2] = q.x + q.y;
                                  ~^~
teste.cpp:37:5: note: in instantiation of function template specialization
      'foo<float *, float>' requested here
    foo(q1, a);
    ^
teste.cpp:20:36: error: member reference base type 'float *const' is not a structure or
      union
    a[1][0] = a[1][1] = a[1][2] = q.y + q.z;
                                  ~^~
teste.cpp:21:36: error: member reference base type 'float *const' is not a structure or
      union
    a[2][0] = a[2][1] = a[2][2] = q.z + q.w;
                                  ~^~
3 errors generated.
4

1 回答 1

3

您可以做的是使用 C++11 中可用的类型特征

您可以声明专用于结构的函数,如下所示:

#include <type_traits>

template <class QT, typename TO, std::enable_if_t<std::is_class<QT>::value, int> = 0>
inline
void foo(const QT q, TO a[][3])
{
    std::cout << "Method 2\n";
    a[0][0] = a[0][1] = a[0][2] = q.x + q.y;
    a[1][0] = a[1][1] = a[1][2] = q.y + q.z;
    a[2][0] = a[2][1] = a[2][2] = q.z + q.w;
}

这将使编译器为结构和类选择此模板,而不是为其他模板。这就是所谓的 SFINAE 技术。

于 2020-08-31T16:18:38.220 回答