有没有一种方法可以在基于枚举的可变参数模板函数之间进行选择,这比将函数包装在结构中更简单

Is there a way of selecting between variadic template functions based on an enum that is simpler than wrapping the functions in a struct?

本文关键字:函数 选择 之间 行选 更简单 结构 包装 变参 方法 一种 于枚举      更新时间:2023-10-16

当前代码如下:

// header file...
enum class FuncType {
    AddTwoInts,
    SquareAnInt
};
template<FuncType F, typename... Ts>
int getValue(Ts...);
// ----------------------------------------
// cpp file...
template<FuncType F>
struct FuncHelper;
template<>
struct FuncHelper<FuncType::AddTwoInts> {
    static int func(int v1, int v2) {return v1 + v2;}
}
template<>
struct FuncHelper<FuncType::SquareAnInt> {
    static int func(int v) { return v*v; }
}
template <FuncType F, typename... Ts>
int getValue(Ts... args) {
    return FuncHelper<F>::func(args...);
}
// explicitly instantiate versions of getValue for each FuncType
// with the correct args...
template int getValue<FuncType::AddTwoInts, int, int>(int , int);
template int getValue<FuncType::SquareAnInt, int>(int)

以上可以通过包含标头然后调用 like 来使用

auto val = getValue<FuncType::AddTwoInts>( 3, 4 );

这是我想要的确切接口,但希望在不需要使用 FuncHelper 或等效的东西的情况下进行实现。有没有办法在编译时更直接地选择可变参数模板?

还有我没有看到的上述问题吗?我上面的实际用例是作为结构类型的工厂功能,该结构类型是一些数据 + 一个 std::函数。

如果你

只是想避免结构,你可以用SFINAE做到这一点。

#include <type_traits>
enum class FuncType {
    AddTwoInts,
    MulTwoInts,
    SquareAnInt,
    ReturnAnInt
};
template<FuncType F, typename... Ts>
int getValue(Ts...);
// ----------------------------------------
// cpp file...
template<FuncType F, typename std::enable_if<F == FuncType::AddTwoInts, int>::type D>
int getValue_aux(int v1, int v2) { return v1 + v2; }
template<FuncType F, typename std::enable_if<F == FuncType::MulTwoInts, int>::type D>
int getValue_aux(int v1, int v2) { return v1 * v2; }
template<FuncType F, typename std::enable_if<F == FuncType::SquareAnInt, int>::type D>
int getValue_aux(int v) { return v * v; }
template<FuncType F, typename std::enable_if<F == FuncType::ReturnAnInt, int>::type D>
int getValue_aux(int v) { return v; }
template<FuncType F, typename... Ts>
int getValue(Ts... args)
{
    return getValue_aux<F, 0>(args...);
}

如果没有辅助函数,就不可能在内部有多个实现,仅仅是因为它们具有不同的arity(所以你需要一个地方来解压缩你的可变参数(。如果所有 impls 都具有相同的参数列表(或者可能的参数列表数量相对较少(,则可以简单地switch FuncType,让优化器在编译时选择正确的参数。

在 C++17 中,您可以执行以下操作:

template<FuncType F, typename... Ts>
int getValue(Ts...args)
{
    if constexpr (F == FuncType::AddTwoInts) {
        static_assert(sizeof...(Ts) == 2, "!");
        return (args + ...);   
    } else {
        static_assert(sizeof...(Ts) == 1, "!");
        const auto& first = std::get<0>(std::tie(args...));
        return first * first;
    }
}

演示