C++模板中的const引用

21
在一个带有通用类型T的C++模板中,我可以使用:
const T &

要获取对常量T的引用。但是,如果现在T本身是一个引用类型(例如T = int&),则上述术语解析为

int &

而不是

const int &

这是有道理的,因为任何引用本身都是常量。但是,是否仍有一种方法可以要求一个

const T &

如果 T 本身是一个引用类型?

编辑:用于评估的示例代码(g++编译器):

template <typename T> class TemplateClass
{
public:
    void foo(const T &bar) { }
};

int main()
{
    TemplateClass<int &> x;
    x.foo(0);   // <-- compile error: no conversion from int to int&
    return 0;
}

5
我不认为它解析为 int&。你为什么认为它会这样做? - Mooing Duck
@MathiasKunter:你为什么认为g++会这样说呢? - Nicol Bolas
2
@NicolBolas:实际上看起来他是对的... http://ideone.com/h7PsC - Matteo Italia
2
但是,Comeau说这是不正确的。所以很可能这是g++的一个bug。 - Matteo Italia
1
甚至在严格模式下,GCC似乎也允许这种方式。引用到引用应该是错误的,而且引用折叠规则直到C++11才被引入。请参见[此处](https://dev59.com/Am865IYBdhLWcg3whfBf)。 - GManNickG
显示剩余3条评论
3个回答

24

移除该引用:

template<typename T>
void Test(const typename std::remove_reference<T>::type & param)
{
        param = 20;
}

现在它按预期工作。


20
这既令人惊叹,又很糟糕。 - tenfour

10

您可以始终使用模板特化来实现任何类型引用的不同版本:

template <typename T> struct X {
  void foo(T const&);
};

template <typename T> struct X<T&> {
  void foo(T const&);
};

现在,X<int>::foo 需要一个 int const&,而 X<int&>::foo 也需要一个 int const&

然而,从你的问题中并不完全清楚你到底想做什么。


编辑:我的 g++ 版本(4.6.1)没有对以下情况进行模板特化而抱怨:

int i = 7;
X<int&>(i);

虽然它确实可以
X<int&>(7);

我认为这是正确的,因为你试图将一个临时变量(7)转换为可变引用(即使它是一个对常量引用的引用)。


编辑2:如果你想减少重复代码,那么不要专门为你的原始类进行特化,而是使用以下方法:

template <typename T> struct R {
  typedef T& Ref;
  typedef T const& ConstRef;
};

template <typename T> struct R<T&> {
  typedef T& Ref;
  typedef T const& ConstRef;
};

template<typename T> struct X {
  void foo(typename R<T>::ConstRef x);
};

是的,这确实可以解决问题。但是如果可能的话,我希望保留使用模板特化的开销。 - emkey08
是的,我想要实现的是 X<int&>(7) 也是有效的(如果参数类型是 const int & 而不是 int &,它将是有效的)。但似乎模板特化是唯一的解决方法,对吗? - emkey08
@MathiasKunter:是的。可以使用我的最小化R类型(在生产代码中更改名称),或者使用std::remove_reference,它可能会执行完全相同的技巧(但您必须自己添加const&)。 - bitmask
@ildjarn 你会如何为那个函数添加专门的功能? - emkey08
1
@MathiasKunter:你可以按照第二次编辑使用traits,但这些是基于特化实现的...但至少它将消除重复实现的需要。你可以使用typename const std::remove_reference<T>::type &作为参数类型(我建议为此使用typedef... - David Rodríguez - dribeas
显示剩余2条评论

1
我遇到了同样的问题。似乎“&”类型转换运算符比“const”限定符更强。因此,当我们有以下代码时:
template<class t>
void fun(const t i)
{
}

fun<int&>();

该函数的类型为void(int&),而不是预期的void(const int&)

为了解决这个问题,我定义了这个模板:

template<class t> struct constify { typedef t type; };
template<class t> struct constify<t&> { typedef const t& type; };

现在将您的函数定义为:

template<class t>
void fun(typename constify<t>::type i)
{
}

fun<int&>();

实例化的函数将具有所需的类型void(const int&)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接