模板通过 const 引用传递

发布于 2024-10-15 11:48:00 字数 1996 浏览 6 评论 0原文

我已经看过一些类似的问题,但我仍然很困惑。我试图弄清楚如何显式(不是通过编译器优化等)和 C++03 兼容来避免在将对象传递给专用模板时复制对象功能。这是我的测试代码:

#include <iostream>

using namespace std;

struct C
{
  C() { cout << "C()" << endl;  }
  C(const C&) { cout << "C(C)" << endl; }
  ~C() { cout << "~C()" << endl;  }
};

template<class T> void f(T) { cout << "f<T>" << endl; }

// This shows two possible ways, I don't need two overloads
// If I do it like (2) the function is not called, only if I do it like (1)

template<> void f(C c) { cout << "f<C>" << endl; } // (1)

template<> void f(const C& c) { cout << "f<C&>" << endl; } // (2)

int main()
{
    C c;
    f(c);
    return 0;
}

(1) 接受 C 类型的对象,并制作一个副本。这是输出:

C()
C(C)
f<C>
~C()
~C()

所以我尝试专门使用 const C& 参数 (2) 来避免这种情况,但这根本不起作用(显然原因在 这个问题)。

好吧,我可以“通过指针传递”,但这有点丑陋。那么有没有一些技巧可以很好地做到这一点呢?

编辑:哦,可能我不清楚。我已经有一个模板化函数

template<class T> void f(T) {...}

,但现在我想专门化这个函数来接受 const&到另一个对象:

template<> void f(const SpecificObject&) {...}

但只有当我将其定义为时才会调用它

template<> void f(SpecificObject) {...}

基本上我想要对这种专业化所做的是将 SpecificObject 适应模板接口,如

template<> void f(SpecificObject obj){ f(obj.Adapted()); } // call the templated version

EDIT2:好的,我可以强制 const C& 专门化以这种方式调用:

f<const C&>(c);

但是有没有办法让它像 f(c) 一样工作?

编辑3:如果有人最终会有类似的问题,我终于在另一个问题中找到了这个链接,它很有帮助: http://www.gotw.ca/publications/mill17.htm

I've looked over a few similar questions, but I'm still confused. I'm trying to figure out how to explicitly (not by compiler optimization etc) and C++03-compatible avoid copying of an object when passing it to a specialized template function. Here is my test code:

#include <iostream>

using namespace std;

struct C
{
  C() { cout << "C()" << endl;  }
  C(const C&) { cout << "C(C)" << endl; }
  ~C() { cout << "~C()" << endl;  }
};

template<class T> void f(T) { cout << "f<T>" << endl; }

// This shows two possible ways, I don't need two overloads
// If I do it like (2) the function is not called, only if I do it like (1)

template<> void f(C c) { cout << "f<C>" << endl; } // (1)

template<> void f(const C& c) { cout << "f<C&>" << endl; } // (2)

int main()
{
    C c;
    f(c);
    return 0;
}

(1) accepts the object of type C, and makes a copy. Here is the output:

C()
C(C)
f<C>
~C()
~C()

So I've tried to specialize with a const C& parameter (2) to avoid this, but this simply doesn't work (apparently the reason is explained in this question).

Well, I could "pass by pointer", but that's kind of ugly. So is there some trick that would allow to do that somehow nicely?

EDIT: Oh, probably I wasn't clear. I already have a templated function

template<class T> void f(T) {...}

But now I want to specialize this function to accept a const& to another object:

template<> void f(const SpecificObject&) {...}

But it only gets called if I define it as

template<> void f(SpecificObject) {...}

Basically what I want to do with this specialization is to adapt the SpecificObject to the template interface like

template<> void f(SpecificObject obj){ f(obj.Adapted()); } // call the templated version

EDIT2: Ok, I can force the const C& specialization to be called this way:

f<const C&>(c);

but is there a way to make it work like this as just f(c)?

EDIT3: If someone would eventually have similar questions, I finally found this link in another question, and it is helpful: http://www.gotw.ca/publications/mill17.htm

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

累赘 2024-10-22 11:48:00

您混淆了三个问题:模板、重载和参数传递。

只需删除特化并将参数作为 T const& 传递即可。

干杯&呵呵,

You're conflating three issues: templates, overloading and argument passing.

Just remove the specializations and pass the argument as T const&.

Cheers & hth.,

自我难过 2024-10-22 11:48:00

你为什么不超载:

void f(const C& c) { cout << "f(const C&)" << endl; }

Why don't you overload:

void f(const C& c) { cout << "f(const C&)" << endl; }
囍孤女 2024-10-22 11:48:00

这可行:

int main()
{
    C c;
    f<const C&>(c);
    return 0;
}

您的替代方案:

template<typename T> void f(const boost::reference_wrapper<T const>& c) 
    { cout << "f<boost_const_ref&>" << endl; } 

int main()
{
    C c;
    f(boost::cref(c));
    return 0;
}

实际上,您可以使用 boost::reference_wrapper 将引用传递到您想要使用它的位置。您可以使用 get() 来执行此操作,尽管 boost::reference_wrapper 具有隐式转换回引用的功能,因此您可能无需模板的部分专业化而只需传递 boost::cref(c ) 到常规的。

This would work:

int main()
{
    C c;
    f<const C&>(c);
    return 0;
}

Your alternative:

template<typename T> void f(const boost::reference_wrapper<T const>& c) 
    { cout << "f<boost_const_ref&>" << endl; } 

int main()
{
    C c;
    f(boost::cref(c));
    return 0;
}

In reality you would use boost::reference_wrapper to pass the reference through to where you want to use it. You can use get() to do that, although boost::reference_wrapper has an implicit conversion back to the reference, so you could probably get by without the partial-specialisation of the template and just passing boost::cref(c) to the regular one.

一抹苦笑 2024-10-22 11:48:00

因此,如果您并不总是想接受 const 引用(这对于基本类型 [int、long、float 等] 是合理的),您可以使用一点 boost 魔法。

#include <iostream>
#include <boost/call_traits.hpp>

using namespace std;

struct C
{
  C() { cout << "C()" << endl;  }
  C(const C&) { cout << "C(C)" << endl; }
  //C& operator=(C const&) { cout << "C=C" << endl; return *this; }
  ~C() { cout << "~C()" << endl;  }
};

template<class T> void foo(typename boost::call_traits<T>::param_type inst) { cout << "f<T>" << endl; }
// specialization for calling class C
template<> void foo<C>(boost::call_traits<C>::param_type inst) { cout << "f<C>" << endl; }

int main()
{
  int i = 0;
  foo<int>(i);
  C c;
  foo<C>(c);
  return 0;
}

So if you don't always want to accept a const reference (which is reasonable for base types [int, long, float etc.]), you can use a little boost magic.

#include <iostream>
#include <boost/call_traits.hpp>

using namespace std;

struct C
{
  C() { cout << "C()" << endl;  }
  C(const C&) { cout << "C(C)" << endl; }
  //C& operator=(C const&) { cout << "C=C" << endl; return *this; }
  ~C() { cout << "~C()" << endl;  }
};

template<class T> void foo(typename boost::call_traits<T>::param_type inst) { cout << "f<T>" << endl; }
// specialization for calling class C
template<> void foo<C>(boost::call_traits<C>::param_type inst) { cout << "f<C>" << endl; }

int main()
{
  int i = 0;
  foo<int>(i);
  C c;
  foo<C>(c);
  return 0;
}
素衣风尘叹 2024-10-22 11:48:00

您的问题是实际参数 c 不是 const,因此主模板是更好的匹配,因为它不需要向类型添加“const”。如果您尝试按值传递和非常量引用传递函数,编译器会告诉您它无法解决该差异。

Your problem is that the actual parameter c isn't const, so the main template is a better match because it doesn't need to add 'const' to the type. If you try functions that pass by value and by non-const reference, the compiler will tell you that it cannot resolve that difference.

呢古 2024-10-22 11:48:00
#include <iostream>

using namespace std;

struct C
{
  C() { cout << "C()" << endl;  }
  C(const C&) { cout << "C(C)" << endl; }
  ~C() { cout << "~C()" << endl;  }
};

template<class T> void f(const T&) { cout << "f<T>" << endl; }

int main()
{
    C c;
    f(c);
    return 0;
}

这确实可以实现您想要的功能,但是您必须对传递到函数中的所有值使用 const ref。我不知道这是否是您正在寻找的。

#include <iostream>

using namespace std;

struct C
{
  C() { cout << "C()" << endl;  }
  C(const C&) { cout << "C(C)" << endl; }
  ~C() { cout << "~C()" << endl;  }
};

template<class T> void f(const T&) { cout << "f<T>" << endl; }

int main()
{
    C c;
    f(c);
    return 0;
}

This does do what you would like, but you must then use a const ref for all values passed into the function. I do not know if this was what you were looking for.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文