4

假设您要编写一个函数,该函数将不透明的句柄传递给未知类型的函数(例如,包含具有商定名称的函数的结构的名称),并将参数转发给该函数。

在非可变情况下,为简单起见考虑单参数函数,有两种方法可以做到这一点:您可以让转发函数接受任意类型的参数,并尝试使用它调用转发函数,编译器会抱怨在模板扩展期间,如果结果不兼容;或者您可以使用 decltype 和各种其他机制来确定转发函数期望的参数类型,并明确要求该类型的参数。我不知道这些是否有任何公认的术语,所以我将称它们为“通过”和“预先”。

pass through 方法直接泛化为具有任意数量参数的函数,但 prefront 方法没有。

#include <iostream>

template<typename T, typename Arg>
void pass_through_1(Arg arg)
{
    T::f(arg);
}

template<typename T> struct arg_of_1;

template<typename Ret, typename Arg>
struct arg_of_1<Ret (Arg)>
{
    typedef Arg type;
};

template<typename T>
void up_front_1(typename arg_of_1<decltype(T::f)>::type arg)
{
    T::f(arg);
}

template<typename T, typename... Args>
void pass_through_var(Args... args)
{
    T::f(args...);
}

template<typename T> struct args_of_var;

template<typename...> struct type_list;

template<typename Ret, typename... Args>
struct args_of_var<Ret (Args...)>
{
    // typedef Args... type; // can't do this
    typedef type_list<Args...> type;
};

// template<typename T>
// void up_front_var(typename args_of_var<decltype(T::f)>::type... args) // can't do this
// {
//     T::f(args...);
// }

struct test  
{ 
    static void f(int x) { std::cout << x*9 << std::endl; }
};

int main(int, char**)
{
    pass_through_1<test>(7);
    up_front_1<test>(8);
    pass_through_var<test>(9);
    // up_front_var<test>(10);
    return 0;
}

问题是不允许参数包是独立的,只能作为模板参数,如果你将它们包装在一个封闭的模板中,就无法将它们解包并解包,只能通过模式匹配。

“预先”具有一些优点,例如更好的自文档化,以及对类型推断的更好支持(up_front<T> 本身可以被 decltyped)。有没有办法让它在可变参数的情况下工作?(你当然可以使用 std::tuple,但这很不令人满意。)

4

2 回答 2

1

没有什么比写下问题更能让你意识到答案的了。

这是一种方法:

template<typename T, typename Args = typename args_of_var<decltype(T::f)>::type>
struct up_front_var;

template<typename T, typename... Args>
struct up_front_var<T, type_list<Args...>>
{
    static void forward(Args... args)
    {
        T::f(args...);
    }
};

我不认为有办法从中创建一个顶级函数(你又遇到了原来的问题),但这可能还不错。

仍然很高兴看到其他解决方案。

于 2011-11-13T01:30:34.500 回答
0

也许我没有正确理解这个问题,但你总是可以省略参数类型,让编译器推断它们。

/* declare */
template<typename T, typename... Args>
void up_front_var(Args... args)
{
    T::f(std::forward<Args>(args)...); // need std::forward to correctly handle lvalue/rvalue references
}

/* an example */
class Test {
public:
    static void f(const char* fmt, int a, int b);
};

void Test::f(const char* fmt, int a, int b)
{
    printf(fmt, a, b); 
}


int main()
{
    up_front_var<Test>("testing %u, %u", 1, 2); // no need to specify arguments here
    return 0;
}
于 2016-06-17T08:58:01.637 回答