关于检查值是否设置的功能的最新技术是什么?
例如,下面的迭代器解析单元格。 有些单元格包含值,其他单元格为空。
最方便的方法是什么?
struct iterator
{ //usage:
bool isset() const // if (it.isset())
bool isSet() const // if (it.isSet())
bool empty() const // if (it.empty())
bool is_set() const // if (it.is_set())
bool is_valid() const // if (it.is_valid())
operator void*() const; // if (it)
explicit operator bool() const; // if ((bool)it) or if(it) //thanks @stijn
operator bool() const; // if (it) //why not implicit conversion?
bool operator!() const; // if (!!it)
//throwing exception as pointed out by @MatthieuM
Type get() { if (isSet()) return value_; else throw; }
//usage:
// try { // if (it.isSet()) {
// Type x = it.get(); // Type x = it.get();
// } // }
// catch (...) { // else {
// //empty // //empty
// } // }
//please feel free to propose something different
...
};
思考:
isset()
=>已重命名为isSet()
empty()
更多关于容器收集,而不仅仅是一个单元格:( operator void*
似乎是合乎逻辑的方式,但deprecated in C++11 streams explicit operator
是not yet supported(我的代码必须符合旧编译器)我正在读:
答案 0 :(得分:6)
void*
存在问题,因为它是一种有效的转换序列,在某些情况下并非有意。许多人在C ++ 03中使用有时称为" safe bool idiom"你有一个包含私有类型的本地成员函数指针类型,所以没有人可以在你的类之外拥有它的实例。但是你可以返回它,至少检查是否为真。
当您使用C ++ 11时,explicit operator bool
是可行的方法,因为它主要是针对这些情况而发明的。
答案 1 :(得分:2)
我对 Imperfect C++: Practical Solutions [...] 的 explicit_cast<T>
没有被提及感到印象深刻。这个概念非常简单 - 你设置了一个伪关键字,它实际上是一个实现你想要的转换的模板类。我一直在我的own C++ backports library中使用它而没有任何重要问题。
class MyClass {
...implementation
operator explicit_cast<bool> () const {
(return a bool somehow)
}
};
您正如您期望的那样使用伪关键字:
MyClass value;
...
if ( explicit_cast<bool>(myobject) ) {
do something
} else {
do something else
}
...
最重要的是,此解决方案可以完美映射到C ++ 11中的本机explicit operator
,从而导致基本上零开销和本机语法。因此,它也比试图判断是否调用“isset”,“is_set”,“is_Set”,“isSet”等更通用...
答案 2 :(得分:1)
大多数情况下,不应使用隐式转换,即在代码中使用operator bool()
等表达式。
如果您希望能够在if
语句中使用您的类的实例,您通常会创建一个隐式转换,但是对于成员函数原型的签名,您将指向一个 - op private function或NULL依赖于状态。
您经常会为您的班级重载bool operator!() const
。由于这将使用与隐式转换相同的逻辑,因此您通常会根据另一个实现一个。
类似的东西:
private:
struct MyPrivateType {};
void MyPrivateFunc( MyPrivateType ) {}
public:
typedef void (&iterator::*)( MyPrivateType ) bool_func;
operator bool_func() const
{
return operator!() ? static_cast<bool_func>(0) : MyPrivateFunc;
}
没有人可以调用你从指针返回的函数,因为它需要一个MyPrivateType,而且它们不能得到一个,因为它是私有的。
答案 3 :(得分:0)
感谢您的所有意见/答案/贡献。在这里,我合并了网上发现的不同想法和其他想法(我已阅读了大量文档和源代码)。
bool isSet()
最合乎逻辑的方式。源代码(库和应用程序)都是初学者可以理解的。这符合KISS principle。此外,它可以作为Java ...
移植到其他编程语言Library: | Application:
|
struct iterator |
{ |
bool isSet() const | if (it.isSet())
{ | {
return p; | int v = it.get();
} | //get() may also call isSet()
|
int get() const | //continue processing
{ | }
return *p; | else //value is not set
} | {
| //do something else
int* p; | }
}; |
如果函数get()
未检查isSet()
且开发人员(应用程序)忘记调用isSet()
(get()
之前),则应用程序代码可能会崩溃(分段错误)。
另一方面,如果get()
函数调用isSet()
,则isSet()
处理执行两次。然而,最近的编译器应该避免这种第二次不必要的isSet()
处理。
Library: | Application:
|
struct iterator | int i = it.get()
{ | if (i >= 0)
int get() const | {
{ | unsigned short v = i;
if(p) return *p; |
else return -1; | //continue processing
} | }
| else //value is not set
unsigned short* p; | {
}; | //do something else
| }
有些人认为异常对于二进制代码优化是不利的。但是,如果内联throw exception
,则最佳编译器可以优化二进制代码,并且优于
此外,此解决方案可能允许最佳优化二进制代码,因为isSet()
被调用两次。但这取决于编译器优化能力。
库:
struct iterator
{
bool get() const
{
if (isSet()) return *p;
else throw;
}
private:
bool isSet() const { return ....; }
....
};
应用:
int value;
try
{
value = it.get();
}
catch (...)
{
value = 0; // default value
}
operator explicit_cast<bool> () const
请参阅写得好的Luis's answer。
operator
编写优雅的if(it)
使用explicit conversion operators introduced in C++11可以很好地实现此解决方案。
库:
struct iterator
{
explicit operator bool() const { return ....; }
....
};
应用:
int value;
if (it) //very elegant C++ fashion
{
value = it.get();
}
else
{
value = 0; // default value
}
但是,我们仍然在2012年,当前的源代码必须与编译器兼容,而不支持显式转换运算符。在论文编制者上,多年来已经实施了不同的可能性。我将在下一章介绍所有这些内容。
if(it)
本章的源代码的灵感来自2004年More C++ idioms撰写的Bjarne Stroustrup一书,更具体地说是@ The Safe Bool Idiom指出的PlasmaHH部分。< / p>
operator bool
当explicit
不可用时,我们可以使用隐式转换运算符。
库:
struct iterator
{
operator bool() const { return ....; } //implicit conversion
....
};
应用:
int value;
if (it) //this works very well!
{
value = it.get();
}
else
{
value = 0; // default value
}
// But these other instructions are also correct :(
int integer = it; //convert it to bool, then convert bool to int
if (-6.7 < it) //.................., then convert bool to double, and compare
it << 1;
operator!
这是boost::thread
(v1.51)中使用的解决方案,作为unique_lock
,shared_lock
,upgrade_lock
和{{3} explicit operator bool()
的变通方法}}
库:
struct iterator
{
bool operator!() const { return ....; }
....
};
应用:
int value;
if (!!it) // !! looks strange for many developers
{
value = it.get();
}
else
{
value = 0; // default value
}
if (it) //ERROR: could not convert ‘it’ from ‘iterator’ to ‘bool’
{
value = it.get();
}
operator void*
这是STL流使用的解决方案。例如,请参阅文件upgrade_to_unique_lock
(std::basic_ios
)。
库:
struct iterator
{
operator void*() const { return ....; }
....
};
应用:
int value;
if (it) //this works very well!
{
value = it.get();
}
else
{
value = 0; // default value
}
// But these other instructions are also correct :(
delete it; //just a warning: deleting 'void*' is undefined
if (it > std::cin) //both are converted to void*
void* r = it;
class
该解决方案由bits/basic_ios.h于1996年提出。
库:
struct iterator
{
private:
class nested; //just a forward declaration (no definition)
int* v_;
public:
operator nested*() const { return v_ ? (nested*)this : 0; }
};
应用:
int value;
if (it) //this works very well!
{
value = it.get();
}
else
{
value = 0; // default value
}
// But these other instructions are also correct :(
iterator it2;
if (it < it2)
int i = (it == it2);
bool
习语
CashCow提出了Bjarne Stroustrup没有缺点。以下是简化版。
库:
struct iterator
{
private:
typedef bool (iterator::*bool_type)() const;
bool private_() const {}
int* v_;
public:
operator bool_type() const { return v_ ? &iterator::private_ : 0; }
};
//forbids it1 == it2
template <typename T>
bool operator == (const iterator& it,const T& t) { return it.private_(); }
//forbids it1 != it2
template <typename T>
bool operator != (const iterator& it,const T& t) { return ! (it == t); }
应用:
int value;
if (it) //this works very well!
{
value = it.get();
}
else
{
value = 0; // default value
}
// All other instructions fail to compile
iterator it2;
if (it > it2) ; //ERROR: no match for ‘operator>’ in ‘it > it2’
if (it == it2) ; //ERROR: ‘bool iterator::private_() const’ is private
if (it != it2) ; //same error
bool
成语这要复杂得多,请参阅utimate solution了解源代码。
库:
struct iterator : safe_bool <iterator> //I do not want virtual functions
{
bool boolean_test() const { return ....; }
....
};
最近的STL和boost提供了设施。一些例子:
safe_bool
:
但是马修威尔逊在他的书Wikibooks中说safe_bool
可能导致编制者没有实施Imperfect C++的规模惩罚。虽然大多数现代编译器在单继承时都会这样做,但是可能存在多重继承的大小惩罚。