假设我们有这段代码:
template <class T, void (*u)(T&)>
void Foo()
{
// store the function u internally . . .
}
有理由做这样的事情,我不会尝试进入它们。但是,有没有办法避免在调用T
时指定类型Foo()
?例如,要编译,通常需要:
Foo<int, MyIntFunction>();
但如果可以从函数指针推导出int
,那么这是可能的:
Foo<MyIntFunction>();
编辑我知道将实际函数指针作为函数参数传递的解决方案,但是这里不需要这样做,因为它在密集循环中有一些缺点。
答案 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的问题。
编辑:否则,即在上面的代码中没有AvoidConversion
,编译器将执行隐式转换,并且参数推导为所有可转换为的类型提供true
彼此(例如,当只有一个函数加倍时,推导出int
。)
如果有人看到了避免这种丑陋AvoidConversion
黑客的方法,并推断出参数类型更加优雅,我会对此感兴趣。