避免指定包含模板化函数指针的冗余模板参数

时间:2014-11-24 19:21:00

标签: c++ templates function-pointers

假设我们有这段代码:

template <class T, void (*u)(T&)>
void Foo()
{
   // store the function u internally . . .
}

有理由做这样的事情,我不会尝试进入它们。但是,有没有办法避免在调用T时指定类型Foo()?例如,要编译,通常需要:

Foo<int, MyIntFunction>();

但如果可以从函数指针推导出int,那么这是可能的:

Foo<MyIntFunction>();

编辑我知道将实际函数指针作为函数参数传递的解决方案,但是这里不需要这样做,因为它在密集循环中有一些缺点。

3 个答案:

答案 0 :(得分:3)

在这个例子中,u不是函数指针,它是一种类型(函数指针的签名)。如果要存储函数指针,则需要传递它。

template<class T, class F = void(*)(T&)>
void Foo(F f)
{
  // store the function pointer f here
}

这样称呼:

struct SomeType {};
void bar(SomeType& x);

Foo(&bar);

这是你的意思吗?

答案 1 :(得分:1)

简短回答:我认为不可能。

Long one ..调用模板函数时,不能省略第一个参数并指定第二个参数:编译器会尝试将MyIntFunction与模板参数T匹配。通常,您可以指定第一个,但如果编译器可以推断第二个模板参数,则省略第二个。在这种情况下,这不是一个选项,因为您要明确指定第二个参数。

第二个模板参数对第一个模板参数具有依赖关系(T)。因此,反转模板参数的顺序也不是一种选择。

你最好的选择是以类似于理查德建议的方式来定义它:

template<class T>
void Foo(T f)
{
   int a(1);
   f(a); // this forces f to be a function taking an int as parameter
}

答案 2 :(得分:1)

这是一个脏实现,基本上是OP所要求的。这取决于太多的假设,但至少可以讨论一些事情。我们的想法是事先指定可用作函数参数的所有可能类型,然后推导出这种类型。

#include<iostream>

template<typename T>
struct TD; //type display

template<typename FunctionType, typename T, typename ... Ts>
struct ArgumentDeduction
{
    typedef typename std::conditional<std::is_same<void, typename std::result_of<FunctionType(T)>::type>::value
                                     , T
                                     , typename ArgumentDeduction<FunctionType, Ts ...>::type
                                     >::type type;
};

template<typename FunctionType, typename T>
struct ArgumentDeduction<FunctionType, T>
{
    typedef typename std::conditional<std::is_same<void, typename std::result_of<FunctionType(T)>::type>::value
                                     , T
                                     , void
                                     >::type type;    
};


template<typename FunctionType
       , typename T = typename ArgumentDeduction<FunctionType, int, double>::type >
void foo()
{
    TD<T>();
}

struct AvoidConversion
{
    struct DummyType{};
    template<typename T> DummyType operator()(T x) { return DummyType(); }    
};

struct Bar : public AvoidConversion
{
    using AvoidConversion::operator();

    void operator()(int x);
    //void operator()(double x);   //try also this
};

int main()
{
    foo<Bar>();  //calls the foo<Bar,int> version    
}

这里的一个主要假设是Bar仿函数的形式,它原则上接受任何类型,但仅对单个允许类型具有类型void的相关实现。

同样,我不认为这是非常有用的,但我想这到目前为止最接近OP的问题。

DEMO


编辑:否则,即在上面的代码中没有AvoidConversion,编译器将执行隐式转换,并且参数推导为所有可转换为的类型提供true彼此(例如,当只有一个函数加倍时,推导出int。)

如果有人看到了避免这种丑陋AvoidConversion黑客的方法,并推断出参数类型更加优雅,我会对此感兴趣。