是否可以通过const引用获取参数,同时禁止转换以便不传递临时值?

Aar*_*aid 5 c++ const

有时我们喜欢通过引用获取一个大参数,并且如果可能的话也使参考const宣称它是一个输入参数.但是通过制作引用const,编译器然后允许自己转换数据,如果它是错误的类型.这意味着它不那么有效,但更令人担心的是我认为我指的是原始数据; 也许我会接受它的地址,而不是意识到我实际上是在接受一个临时的地址.

bar此代码中的调用失败.这是可取的,因为引用的类型不正确.调用bar_const也是错误的类型,但它默默地编译.这对我来说是不受欢迎的.

#include<vector>
using namespace std;

int vi;

void foo(int &) { }
void bar(long &) { }
void bar_const(const long &) { }

int main() {
   foo(vi);
   // bar(vi); // compiler error, as expected/desired
   bar_const(vi);
}
Run Code Online (Sandbox Code Playgroud)

传递轻量级只读引用最安全的方法是什么?我很想创建一个类似于参考的新模板.

(显然,int并且long是非常小的类型.但是我已经遇到了可以相互转换的更大的结构.当我采用const引用时,我不希望这种情况无声地发生.有时,将构造函数标记为明确的帮助,但这并不理想)

更新:我想象一个如下系统:想象一下有两个函数X byVal();X& byRef();下面的代码块:

 X x;
 const_lvalue_ref<X> a = x; // I want this to compile
 const_lvalue_ref<X> b = byVal(); // I want this to fail at compile time
 const_lvalue_ref<X> c = byRef(); // I want this to compile
Run Code Online (Sandbox Code Playgroud)

该示例基于局部变量,但我希望它也可以使用参数.我希望得到某种错误消息,如果我不小心将ref-to-temporary或ref-to-a-copy传递给我认为我会传递一些轻量级的内容,例如ref-to-lvalue.这只是一个'编码标准'的东西 - 如果我真的想允许将ref传递给临时的,那么我会直截了当地使用const X&.(我发现Boost的FOREACH中的这篇文章非常有用.)

Tom*_*ock 7

好吧,如果你的"大参数"是一个类,首先要做的是确保你明确标记任何单个参数构造函数(除了复制构造函数):

class BigType
{
public:
    explicit BigType(int);
};
Run Code Online (Sandbox Code Playgroud)

这适用于具有可能使用单个参数调用的默认参数的构造函数.

然后它将不会自动转换为,因为没有隐式构造函数供编译器用于执行转换.您可能没有任何构成该类型的全局转换运算符,但如果您这样做,那么

如果这对您不起作用,您可以使用一些模板魔术,例如:

template <typename T>
void func(const T &); // causes an undefined reference at link time.

template <>
void func(const BigType &v)
{
    // use v.
}
Run Code Online (Sandbox Code Playgroud)


Aar*_*aid 0

(回答我自己的问题,感谢我在另一个问题上的出色回答。谢谢@hvd。)

简而言之,将函数参数标记为volatile意味着它不能绑定到右值。(任何人都可以为此确定一个标准引用吗?临时对象可以绑定到const&,但const volatile &显然不能绑定到 。这就是我在 g++-4.6.1 上得到的。(额外:请参阅此扩展评论流以了解一些血淋淋的细节,这些细节已经过去了我的头 :-) ))

void foo( const volatile Input & input, Output & output) {
}

foo(input, output); // compiles. good
foo(get_input_as_value(), output); // compile failure, as desired.
Run Code Online (Sandbox Code Playgroud)

但是,您实际上并不希望参数为volatile。所以我写了一个小包装来将 const_castvolatile去掉。所以 foo 的签名变成这样:

void foo( const_lvalue<Input> input, Output & output) {
}
Run Code Online (Sandbox Code Playgroud)

包装器在哪里:

template<typename T>
struct const_lvalue {
    const T * t;
    const_lvalue(const volatile T & t_) : t(const_cast<const T*>(&t_)) {}
    const T* operator-> () const { return t; }
};
Run Code Online (Sandbox Code Playgroud)

这只能从左值创建

有什么缺点吗?这可能意味着我不小心误用了一个真正不稳定的对象,但话又说回来,我以前从未使用过volatile。所以我认为这对我来说是正确的解决方案。

我希望养成默认情况下使用所有合适参数执行此操作的习惯。

ideone 上的演示