c++ - 从静态成员函数推断类模板参数的模式

标签 c++ templates c++17

我的情况

我有两个类,由不受我控制的外部库提供,例如他们的界面对我来说是固定的。

第一个是模板化的二维容器类型,它允许我操作通过成员函数以及原始指针保存的内容。
第二个是一个包含一堆静态成员函数的类,这些函数抽象了一些经过 SIMD 优化的 vector 操作。它们中的大多数都被重载以采用不同的数据类型,但是它们都共享相同的接口(interface),例如

VecOperations::op (Type* dest, const Type* src, /* a variable number of operation specific arguments */, int len)

我想要达到的目标:

我想迭代我的 2D 容器的第一个维度,并在第二次迭代中对每个 vector 应用 vector 操作。因此我想更换例如
auto** ptrs = conatiner.getArrayOfRawPointers();
for (int i = 0; i < container.getXDim(); ++i)
    VecOperations::foo (ptrs[i], ptrs[i], arg1, arg2, arg3, container.getYDim());

理想情况下是这样的(伪代码)
forAllElements<VecOperations::foo> (container, arg1, arg2, arg3);

这应该适用于存储在我的容器中的所有类型的类型,这些类型受 vector 操作类的支持,也适用于所有数量的 vector 操作特定参数。据我所知,写一些类似 forAllElements以上是不可能的。

我目前的解决方案:

我想出了这个:
template <typename ElemType, typename ...Args>
struct ForAllElemements
{
    template <void(*op)(ElemType*, const ElemType*, Args..., int)>
    static void call (Container<ElemType>& buffer, Args... args)
    {
        auto xDim = container.getXDim();
        auto yDim = container.getYDim();
        auto** ptrs = conatiner.getArrayOfRawPointers();

        for (int i = 0; i < xDim; ++i)
            op (ptrs[i], const_cast<const ElemType*>(ptrs[i]), args..., yDim);
    }
};

这可以像这样使用
// using a Container<float> and VecOperations::foo (float*, const float*, float, int, float, int)

ForAllElemements<float, float, int, float>::call<VecOperations::foo> (container, arg1, arg2, arg3);

虽然在 C++17 中从构造函数中推导出类模板参数是可行的,但据我所知,从静态函数调用中推导出它是行不通的。据我了解,这根本没有定义,从技术上讲,我看不出任何原因
ForAllElemements::call<VecOperations::foo> (container, arg1, arg2, arg3);


应该是不可能的,因为所有模板类型都可以从传递给静态函数的参数中推断出来。

所以我问你,是否有任何我不知道的 super 聪明的解决方法或模式可以让 C++17 或更高版本的标准实现这样的事情?

最佳答案

类模板参数推导仅基于类对象的初始化程序发生。在这里,您甚至不需要类类型的对象,只需要使用静态成员函数。

但是备份,也许一个普通的函数模板可以工作:

// C++20 will define std::type_identity_t; or just define your own:
template <typename T>
struct type_identity { using type = T; };
template <typename T>
using type_identity_t = typename type_identity<T>::type;

template <typename ...Args, typename ElemType>
void forAllElements(
    Container<ElemType> &c,
    void (*op)(ElemType*, const ElemType*, type_identity_t<Args>..., int), 
    Args...);

函数指针在这里确实需要是函数参数而不是模板参数。这适用于普通 Args...在函数指针签名中而不是 type_identity_t<Args>...如果函数重载,但函数未重载,编译器可能需要 type_identity_t ,大概是为了确保 Args是在一个非推断的上下文中。 (我认为标准中有一个不清楚的要求导致一些不同的结果......)

备注 Args只能从 forAllElements 的参数推导出来而不是来自函数类型,并且函数类型需要完全匹配。因此,如果您允许推导这些类型,则需要注意传入的表达式的确切类型。如有必要,请转换它们。如果使用文字作为常量值,您可以使用 1.0f 之类的形式获取 float类型等。或者,您可以指定参数类型,如 forAllElements<float, int, float> ,这就是为什么我把 ...Args之前 ElemType在模板中(尽管现在 ElemType 永远不能明确给出,必须从容器参数中推导出来)。

关于c++ - 从静态成员函数推断类模板参数的模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60935388/

相关文章:

c++ - CMake set_target_properties 和 include_directories

templates - 跨继承模板组合 Assetic 资源

C++:如何从 make_shared 部分推导模板参数

c++ - 将 CTAD 与多个模板参数包一起应用

c++ - 在图像顶部模拟天体(星星)

c++ - 如何在QT中写一个旋转里程表?

c++ - Visual Studio 2010 C++ : malloc()/HeapAlloc always allocates new page for even smallest alloc size

templates - jbot 没有覆盖我的模板

c++ - 如何推断嵌套容器值类型

c++ - 使用/std :c++latest (or C++17/N4190) 使用 MSVC2015 编译 boost