C++ 如何在c+;中为采用模板化参数并对其应用模板化函数的函数设置模板+;?

C++ 如何在c+;中为采用模板化参数并对其应用模板化函数的函数设置模板+;?,c++,templates,function-pointers,alias,member-function-pointers,C++,Templates,Function Pointers,Alias,Member Function Pointers,我有一堆静态类函数,它们接受不同数量的{string,int,float}参数和一个输出参数。根据调用的函数,相同参数可能有不同的行为。例如: static void ChangeOutput1(const string& foo, int bar, Output* output); static void ChangeOutput2(int bar, Output* output); static void ChangeOutput3(float foo, Output* output

我有一堆静态类函数,它们接受不同数量的{string,int,float}参数和一个输出参数。根据调用的函数,相同参数可能有不同的行为。例如:

static void ChangeOutput1(const string& foo, int bar, Output* output);
static void ChangeOutput2(int bar, Output* output);
static void ChangeOutput3(float foo, Output* output);
static void ChangeOutput4(float foo, Output* output);  // behaves differently from ChangeOutput3
我希望有一种简单、安全的方法来编写模板,以便在每个函数上执行类似的行为,基本上是使用输出参数调用并将其转换为字符串以返回。理想情况下,无需再次指定参数类型。它可能看起来像这样:

template<typename... Args, int (*ChangeOutputFn)(Args...)>
string OutputString(Args... args) {
    Output output;
    ChangeOutputFn(args..., &output);
    return ConvertToString(output);
}

// Is there a way to alias static templated functions?
using StringOutput1 = OutputString<ChangeOutput1>;
using StringOutput2 = OutputString<ChangeOutput2>;
using StringOutput3 = OutputString<ChangeOutput3>;
auto a1 = mkOutput(ChangeOutput1);
auto a2 = mkOutput(ChangeOutput2);
auto a3 = mkOutput(ChangeOutput3);
auto a4 = mkOutput(ChangeOutput4);
模板
字符串输出字符串(Args…Args){
产量;
ChangeOutputFn(参数…,&output);
返回转换器字符串(输出);
}
//有没有办法别名静态模板化函数?
使用StringOutput1=OutputString;
使用StringOutput2=OutputString;
使用StringOutput3=OutputString;

我不知道如何才能做到这一点。我既不确定如何编写OutputString,也不确定如何别名或定义静态函数。有一些不那么优雅的解决方案,但它们需要重复的样板文件,我希望避免这种情况。

对于一个类,您可以执行以下操作:

template <typename T, T f> struct OutputString;

template<typename... Args, void (*ChangeOutputFn)(Args...)>
struct OutputString<void (*)(Args...), ChangeOutputFn>
{
    template <typename ... Ts>
    auto operator()(Ts... args)
    -> decltype(ChangeOutputFn(std::forward<Ts>(args)..., std::declval<Output *>()),
                std::string{})
    {
        Output output;
        ChangeOutputFn(std::forward<Ts>(args)..., &output);
        return ConvertToString(output);
    }
};

如果将输出参数移到前面,则可以执行此操作

static void ChangeOutput1(Output*, const std::string& foo, int bar);
static void ChangeOutput2(Output*, int bar);
static void ChangeOutput3(Output*, float foo);
static void ChangeOutput4(Output*, float foo);
现在您可以使用此模板:

template<typename... Args>
std::function<std::string(Args...)>
mkOutput (void (*ChangeOutputFn)(Output*, Args...))
{
    return [ChangeOutputFn](Args... args)->std::string{
        Output output;
        ChangeOutputFn(&output, args...);
        return ConvertToString(output);
    };
}
注1。不能使用此语法

OutputString<ChangeOutput1>
然后用宏消除重复,但那太难看了


我选择在运行时而不是在编译时传递函数,这样更容易。

只需给它们取相同的名称(即重载,不使用模板)。Für C++11,看看可变模板。但是,我没有检查它是否能完全满足您的所有需求requirements@n.m.-我不能给他们都起同样的名字;对于不同的情况,同一个签名可能具有不同的语义(例如,有多个情况只需要一个int,但输出的内容不同)。疯狂的模板魔术,但可能问题一开始就不必要地复杂。为什么不简单地重载相同的函数,类似于
std::to_string()
?@Jarod42使用c++11编译此代码时会出现错误“'int(int,struct Output*)”不是使用StringOutput1=OutputString的模板非类型参数的有效类型;”我遗漏了什么?@Walter它不能重载,因为ChangeOutput3和ChangeOutput4具有完全相同的属性signature@Jarod42好的,我知道了。decltype不执行指向函数衰减的指针,因此“using”行必须是decltype(&ChangeOutput1).@LoPiTaL:Demo已添加,编译已修复。
auto a1 = mkOutput(ChangeOutput1);
auto a2 = mkOutput(ChangeOutput2);
auto a3 = mkOutput(ChangeOutput3);
auto a4 = mkOutput(ChangeOutput4);
OutputString<ChangeOutput1>
OutputString<decltype(ChangeOutput1), ChangeOutput1>