将运行时变量简洁地映射到模板参数,用于_many_函数

问题描述 投票:0回答:1

问题

我有一个模板化函数

template <int N>
void myfunc(int a) {

    // contents compile-time optimised using N
}

我在编译时实例化,为不同的

N
做出独特的定义。在运行时,我需要使用用户给定变量通知的模板参数来调用
myfunc

一个详细的方法是:

void callOptimisedMyFunc(int n, int a) {
    if (n == 0) myfunc<0>(a);
    if (n == 1) myfunc<1>(a);
    if (n == 2) myfunc<2>(a);
    // ...
    if (n == MAX) myfunc<MAX>(a);
}

在我的例子中是非常长的,因此

MAX
可以和
64
一样大。更糟糕的是,我需要为大约 ten 具有独特签名和返回类型的不同函数创建这样的包装器!例如

template <int N>
long otherFunc(string x, double y) {
    
    // ...

} 

void callOptimisedOtherFunc(int n, string x, double y) {
    if (n == 0) return otherfunc<0>(x, y);
    if (n == 1) return otherfunc<1>(x, y);
    if (n == 2) return otherfunc<2>(x, y);
    // ...
    if (n == MAX) return otherfunc<MAX>(x, y);
}

我希望以元编程方式执行运行时到编译时参数的映射。 不满意的解决方案

我目前的冗长解决方案是使用日志深度宏:

#define NORETURN #define INNER1(usernum, compnum, func, args, retcmd) \ if (usernum == compnum) retcmd func<compnum> args; #define INNER4(usernum, compbase, func, args, retcmd) \ INNER1( usernum, compbase+0, func, args, retcmd ); \ INNER1( usernum, compbase+1, func, args, retcmd ); \ INNER1( usernum, compbase+2, func, args, retcmd ); \ INNER1( usernum, compbase+3, func, args, retcmd ); #define INNER16(usernum, compbase, func, args, retcmd) \ INNER4( usernum, compbase+0, func, args, retcmd ); \ INNER4( usernum, compbase+4, func, args, retcmd ); \ INNER4( usernum, compbase+8, func, args, retcmd ); \ INNER4( usernum, compbase+12, func, args, retcmd ); #define INNER64(usernum, func, args, retcmd) \ INNER16( usernum, 0, func, args, retcmd ); \ INNER16( usernum, 16, func, args, retcmd ); \ INNER16( usernum, 32, func, args, retcmd ); \ INNER16( usernum, 48, func, args, retcmd ); #define CALL_OPTIMISED_FUNC(n, func, ...) \ INNER64( n, func, (__VA_ARGS__), NORETURN ); #define CALL_AND_RETURN_OPTIMISED_FUNC(n, func, ...) \ INNER64( n, func, (__VA_ARGS__), return );

这让我可以跑步:

void callOptimisedMyFunc(int N, int a) { CALL_OPTIMISED_FUNC( N, myfunc, a ); } long callOptimisedOtherFunc(int N, string x, double y) { CALL_AND_RETURN_OPTIMISED_FUNC( N, otherfunc, x, y ); }

这仍然是令人不舒服的冗长,并且没有使用 C++17 中提供的所有漂亮的 C++ 元编程工具。在每次调用时不必要地评估 64 个 
if

语句似乎也是一种耻辱。更令人满意的解决方案是准备一个函数指针的静态数组,由它们的模板参数索引

N
部分解决方案

如果我只有一个

single

模板化函数要调用(即只有myfunc),我可以像这样使用

index_sequence
#include <array>
#include <utility>

template<size_t... N>
constexpr auto helper_myfunc(index_sequence<N...>) {

    return array <void (*)(int), sizeof...(N)> { myfunc<N> ... };
}

constexpr auto getArrayOfMyFuncRefs() {

    return helper_myfunc( make_index_sequence<MAX>() );
}

这可以让我简洁地写

void callOptimisedMyFunc(int n, int a) { static auto funcs = getArrayOfMyFuncRefs(); funcs[n](a); }

唉,我需要为其他我希望将运行时参数映射到编译时参数的函数复制此定义:

template<size_t... N> constexpr auto helper_otherfunc(index_sequence<N...>) { return array <long (*)(string, double), sizeof...(N)> { otherfunc<N> ... }; } constexpr auto getArrayOfOtherFuncRefs() { return helper_otherfunc( make_index_sequence<MAX>() ); }

long callOptimisedOtherFunc(int n, string x, double y) {

    static auto funcs = getArrayOfOtherFuncRefs();
    return funcs[n](x, y);
}
寻求解决方案

我试图将上面的

getArray*()

函数概括为一个接受

any
单整数模板化函数的函数,即使具有不同的签名。这将使我能够简洁地定义: void callOptimisedMyFunc(int n, int a) { static auto funcs = getArrayOfFuncRefs(myfunc); funcs[n](a); } void callOptimisedOtherFunc(int n, string x, double y) { static auto funcs = getArrayOfFuncRefs(otherfunc); return funcs[n](x, y); }

我正在努力做到这一点,因为我不知道如何将像 
myfunc

这样的引用传递给函数;它缺少模板语法(即

<0>
)。我最近的努力没有编译:
template<size_t... N, typename RetType, typename... Args>
constexpr auto helper(index_sequence<N...>, ReturnType (*funcname)(Args...)) {

    return array<RetType (*)(Args...), sizeof...(N)>{ funcname<N> ... };
}

template<typename Func>
constexpr auto getArrayOfFuncRefs(Func func) {

    return helper(make_index_sequence<MAX>(), func);
}

有没有办法通过 C++ 元编程实现我想要的目标,或者我必须退回到宏的可怕用法?

c++ templates c++17 template-meta-programming index-sequence
1个回答
0
投票

// Need one of these for each function template template <int N> struct MyFuncWrapper { static void call(int a) { myFunc<N>(a); } }; template <template <int N> class Wrapper, typename... Args, size_t... Is> void CallOptimizedHelper(std::index_sequence<Is...>, int n, Args&&... args) { ((n==Is ? (void)Wrapper<Is>::call(std::forward<Args>(args)...) : (void)0), ...); } template <template <int N> class Wrapper, typename... Args> void CallOptimized(int n, Args&&... args) { CallOptimizedHelper<Wrapper>( std::make_index_sequence<MAX>{}, n, std::forward<Args>(args)...); }

然后你称其为

CallOptimized<MyFuncWrapper>(/*n=*/1, /*a=*/2);

	
© www.soinside.com 2019 - 2024. All rights reserved.