关于C++:如何防止r-value

How to prevent an r-value

我正在创建这样一个函数:

1
2
3
4
void SetItem(const Key &key, const Value &value)
{
    ...
}

其中键和值是某种类型。

在内部,我希望像这样存储这对:

1
std::pair<const Key &, Value>

所以我的问题是:我需要强制该键实际上是一个L值,这样在函数退出时它就不会被清除(R值不安全)

我可以在函数上签名:

1
void SetItem(Key &key, const Value &value)

这将阻止使用r值,但它不允许使用const键,我也不喜欢。

在保持常量的同时,有没有一种方法可以强制键成为l值?

我可以创建一个R值过载来防止它:

1
2
3
4
void SetItem(Key &&key, const Value &value)
{
     [What do I put here?]
}

谢谢


随着注释合并的改进,在完全符合C++ 11编译器的情况下,它应该是这样的:

1
2
3
4
5
6
class X{
public:
  void SetItem(Key const& key, Value const& value);
private:
  void SetItem(Key const&&, Value const&) = delete;
};

私有过载将捕获所有Key个值。访问检查不是在过载解决过程中完成的,因此我们可以把它放在private下,这样可能的friend在编译时也会得到一个很好的错误消息,我们= delete它。

对于尚不支持显式删除函数的编译器,您可以将其保持为未定义状态,但对于可能的friends,这只会显示为链接器错误。但是,一般的访问群体会收到"setitem"is unaccessible"编译器错误消息。:)


除了@xeo的答案,你也可以

1
2
3
4
template<typename T = int> // thanks to Xeo for suggesting the default parameter
void SetItem(Key&& key, const Value& value) {
    static_assert(sizeof(T) == 0,"SetItem cannot be used with temporary values as keys");
}

这比在编译时不定义提供给定错误消息的函数有优势,而不是得到一个无效的链接器错误。

注意,static_assert必须依赖于template参数,这样它只会在使用时出错。否则,即使没有在任何地方调用编译器,编译器也可以自由编译它,并且它将一直出错。