我有以下代码:
template <typename T>
void f1( T t )
{
std::cout << "f1( " << t << " ) called." << endl;
}
template <typename T>
void f2( T t )
{
std::cout << "f2( " << t << " ) called." << endl;
}
template <typename F, typename T>
void call( F && f, T t )
{
f( t );
}
template <typename T>
void foo( T t )
{
call( f1<T>, t ); // Why is <T> necessary?
// f1(t) is a valid expression!
call( f2<T>, t );
}
void bar()
{
foo( 1 );
}
在函数foo()
中,我需要指定模板参数,即使f1(t)
是有效表达式。这有点破坏了我的代码中的一些可能性。我的问题:
(顺便说一句:我目前正在使用Visual Studio 2010,如果我将<T>
退出,我会收到错误C2896。)
答案 0 :(得分:11)
f1
不是函数,它是一个模板。您不能将模板作为函数参数传递。
f1<T>
是一个函数,因此可以传递。
答案 1 :(得分:8)
<强> 1。为什么我需要指定模板参数?
嗯,f1
不是一个对象,而是一个函数模板。您只能将对象传递给函数。
<强> 2。我该如何解决这个限制? (允许使用C ++ 11或C ++ 14。)
使用带有模板化operator()
的对象。只需将f1()
的定义替换为
struct { template <typename T> void operator()( T t )
{
std::cout << "f1( " << t << " ) called." << endl;
} } f1;
同样适用于f2()
。在C ++ 14中,您可以更好地编写它
static const auto f1 = []( auto t )
{
std::cout << "f1( " << t << " ) called." << endl;
};
答案 2 :(得分:3)
您可以尝试将模板化函数f1和f2包装在非模板化类中,并传递实例(甚至类型),例如。
struct F1
{
template <typename T>
void operator()(T t) const
{
std::cout << "F1::operator()(" << t << ") called" << std::endl;
}
};
struct F2
{
template <typename T>
void operator()(T t) const
{
std::cout << "F2::operator()(" << t << ") called" << std::endl;
}
};
template <typename F, typename T>
void call(F && f, T t)
{
f(t);
}
template <typename T>
void foo(T t)
{
static const F1 f1;
static const F2 f2;
call(f1, t);
call(f2, t);
}
void bar()
{
foo(1);
}
产生输出:
F1 :: operator()(1)调用
F2 :: operator()(1)名为
答案 3 :(得分:1)
f1(t)
不是有效表达式,因为没有函数f1
。只有一个名为f1
的模板,可以在编译时生成函数f1<T>
。
您谈到的限制是编译时类型检查的直接后果。如果您在编译时知道foo的参数类型,则没有限制,因为您可以轻松添加它。如果您不知道参数的类型,则可能必须使用派生类模型而不是模板驱动的想法。
答案 4 :(得分:1)
有一种方法可以模仿传递函数模板(或重载集)作为第一类值:通过将它们转换为函数对象来“reify”它们。您的代码可以像这样重写:
struct F1
{
template <typename T>
void operator ()( T t )
{
std::cout << "f1( " << t << " ) called." << endl;
}
} f1;
struct F2
{
template <typename T>
void operator ()( T t )
{
std::cout << "f2( " << t << " ) called." << endl;
}
} f2;
// Note that this function didn't change at all!
template <typename F, typename T>
void call( F && f, T t )
{
f( t );
}
// Neither did this, expect that now you don't need the <T>
template <typename T>
void foo( T t )
{
call( f1, t );
call( f2, t );
}
void bar()
{
foo( 1 );
foo( 3.14 );
foo( "Hello World" );
}
答案 5 :(得分:0)
我想提供的是针对您的问题的可能解决方法。但是,由于OP提供的有关您特定设计要求的信息有限,我无法确切地说明这是否适合您的情况。
第一步是将f1
和f2
转换为模板仿函数类:
template <typename T>
class f1 {
public:
void operator ()( T t ) {
std::cout << "f1( " << t << " ) called." << std::endl;
}
};
(同样适用于f2
。)通过这种方式,您可以将f1
(而不是f1<T>
)作为模板模板参数传递给call
,现在已在这样:
template <template <typename> class F, typename T>
void call( T t )
{
F<T> f;
f( t );
}
请注意,F
是一个模板模板参数,它绑定到采用一个模板类型参数的模板类(例如f1
)。
最后,foo
成为了这个:
template <typename T>
void foo( T t )
{
call<f1>( t );
call<f2>( t );
}
bar
与以前一样。