模板函数作为模板参数 我刚刚开始困惑,如何在C++中以通用的方式实现某些东西。这有点复杂,所以让我一步一步地解释
考虑这样的代码:模板函数作为模板参数 我刚刚开始困惑,如何在C++中以通用的方式实现某些东西。这有点复杂,所以让我一步一步地解释,c++,templates,dry,generic-programming,C++,Templates,Dry,Generic Programming,考虑这样的代码: void a(int) { // do something } void b(int) { // something else } void function1() { a(123); a(456); } void function2() { b(123); b(456); } void test() { function1(); function2(); } 很容易注意到,function1和functi
void a(int) {
// do something
}
void b(int) {
// something else
}
void function1() {
a(123);
a(456);
}
void function2() {
b(123);
b(456);
}
void test() {
function1();
function2();
}
很容易注意到,function1
和function2
的作用是相同的,唯一不同的部分是内部函数
因此,我想使函数
通用,以避免代码冗余。我可以使用函数指针或模板来完成。现在让我选择后者我的想法是这样更好,因为编译器肯定能够内联函数-我说的对吗?如果调用是通过函数指针进行的,编译器是否仍然可以内联调用?这是一个附带问题
好的,回到原点。。。具有模板的解决方案:
void a(int) {
// do something
}
void b(int) {
// something else
}
template<void (*param)(int) >
void function() {
param(123);
param(456);
}
void test() {
function<a>();
function<b>();
}
我知道模板参数可以是以下参数之一:
- a型
- 模板类型
- 一种类型的值
function()
?
(是的,函数指针在这种情况下似乎是一种解决方法——只要它们也可以内联——但我正在寻找这类问题的通用解决方案)。这里有一种方法。它可能不是最好的,但它是有效的:
template <typename T, T param>
void function() {
param(123);
param(456);
}
void test()
{
function< void(*)(int), a<int> >(); // space at end necessary to compiler
function< void(*)(int), b<int> >(); // because the C++ grammar is ambiguous
}
模板
空函数(){
param(123);
param(456);
}
无效测试()
{
函数();//编译器所需的末尾空格
函数<空格(*)(int),b>();/ /因为C++语法不明确
}
它们是否内联取决于编译器,但如果它们没有内联,我会很惊讶
编辑:好的,我今天有点休息,错过了参数类型不同的部分。我的错
使用模板可能有一种棘手的方法,但这是我能想到的最简单的方法:
#define function(x) do { x<thing1>(obj1); x<thing2>(obj2) } while(0)
#定义函数(x)do{x(obj1);x(obj2)}while(0)
我知道,我知道,“宏是邪恶的,”诸如此类。它起作用了。如果
函数
需要比您的示例更复杂,您可能会遇到问题,但这比我能想到的任何东西都要简单。为了解决模板的这个问题,您必须使用模板参数。
不幸的是,您不能将模板函数作为类型传递,因为必须首先实例化它。但是有一个虚拟结构的解决方案。以下是一个例子:
template <typename T>
struct a {
static void foo (T = T ())
{
}
};
template <typename T>
struct b {
static void foo (T = T ())
{
}
};
struct SomeObj {};
struct SomeOtherObj {};
template <template <typename P> class T>
void function ()
{
T<SomeObj>::foo ();
T<SomeOtherObj>::foo ();
}
int main ()
{
function<a>();
function<b>();
}
模板
结构a{
静态void foo(T=T())
{
}
};
模板
结构b{
静态void foo(T=T())
{
}
};
结构SomeObj{};
结构SomeOtherObj{};
模板
空洞函数()
{
T::foo();
T::foo();
}
int main()
{
函数();
函数();
}
模板
空洞函数(F)
{
f(123);
}
void a(int x){…}
结构b{void operator()(int x){…};
无效外()
{
功能&a;
函数(b());
}
使用C++14中的通用lambda,您可以执行以下操作:
template<typename T> void a(T t) { /* do something */}
template<typename T> void b(T t) { /* something else */ }
template <typename F>
void function(F&& f) {
f(someobj);
f(someotherobj);
}
void test() {
// For simple cases, auto&& is even probably auto or const auto&
function([](auto&& t){ a(t); });
function([](auto&& t){ b(t); });
// For perfect forwarding
function([](auto&& t){ a(std::forward<decltype(t)>(t)); });
function([](auto&& t){ b(std::forward<decltype(t)>(t)); });
}
template void a(T){/*做点什么*/}
模板void b(T T){/*其他东西*/}
模板
无效函数(F&&F){
f(someobj);
f(其他对象j);
}
无效测试(){
//对于简单的情况,auto&&甚至可能是auto或const auto&
函数([](auto&t){a(t);});
函数([](auto&t){b(t);});
//完美转发
函数([](auto&t){a(std::forward(t));});
函数([](auto&t){b(std::forward(t));});
}
如果调用是通过函数指针进行的,编译器仍然可以内联调用吗
它们可以,但它确实更复杂,并且可能比使用functor或template失败的次数更多。但是请注意,
函数
将要调用参数模板函数的不同实例化。@Kos-是不是#define
不可能?好吧,这是一个“最后的办法”,它会起作用:),但是编辑、调试、不能在名称空间中是不舒服的。。。我更喜欢找到一个基于模板而不是基于预处理器的解决方案。不太清楚为什么这会被否决。这并不完全令人满意,但它解决了问题。所以总结一下:唯一可以内联调用的解决方案是用functor替换函数?有点笨拙,但我认为完全可以接受。谢谢但我承认,在你说不可能通过地址呼叫内联后,我非常惊讶。。。如果在编译时可以确定地址等于给定函数的地址,我希望编译器足够聪明。:)奇怪……我用g++4.5运行了一次,得到了相反的结果:@Kos:你的测试太简单了,gcc足够聪明,可以优化简单的静态代码块。尝试一些更接近现实的东西。顺便说一句,同时指定-O3
和-Os
是没有意义的。如果您使用多个-O选项,无论有无级别编号,最后一个这样的选项都是有效的。这不是OP想要的。谢谢,但这与我描述的问题无关。在这种情况下,给定的函数
调用只使用一个参数函数/函子的实例化。请再读一遍这个问题。通用lambda是C++14的一部分。@mariusm:的确,措辞已经修正。
template < typename F >
void function(F f)
{
f(123);
}
void a(int x) { ... }
struct b { void operator() (int x) { ... } };
void outer()
{
function(&a);
function(b());
}
template<typename T> void a(T t) { /* do something */}
template<typename T> void b(T t) { /* something else */ }
template <typename F>
void function(F&& f) {
f(someobj);
f(someotherobj);
}
void test() {
// For simple cases, auto&& is even probably auto or const auto&
function([](auto&& t){ a(t); });
function([](auto&& t){ b(t); });
// For perfect forwarding
function([](auto&& t){ a(std::forward<decltype(t)>(t)); });
function([](auto&& t){ b(std::forward<decltype(t)>(t)); });
}