我有一个类似可选类的类(因为它在C ++ 17中,所以我不能使用可选类)。它包含一个(可能的)值以及一个指示其是否有效的标志。我有一个显式的布尔运算符和一个转换运算符来获取值。问题是,有时C ++会在显式bool上下文(if语句)中选择bool运算符,而其他时候则不会。谁能帮助我了解这种行为:
#include <algorithm>
#include <stdexcept>
template <typename T>
struct maybe {
maybe() : valid_(false) {}
maybe(T value) : valid_(true) { new (&value_) T(value); }
operator T&&() {
return std::move(value());
}
explicit operator bool() const {
return valid_;
}
T& value() {
if (!valid_) {
throw std::runtime_error("boom");
}
return value_;
}
private:
union {
T value_;
};
bool valid_;
};
int main() {
// fine, uses operator bool()
maybe<std::pair<int,int>> m0;
if (m0) {
std::pair<int,int> p = m0;
(void)p;
}
// throws error, uses operator T&&()
maybe<double> m1;
if (m1) {
double p = m1;
(void)p;
}
}
答案 0 :(得分:4)
只要您写:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<head>
<meta http-equiv="author" content="Chris" />
<script>
$(function() {
jQuery('#one').hide();
jQuery('#fadeToggle').click(function() {
jQuery('#one').fadeToggle(500);
});
jQuery('#fadeTo').click(function() {
jQuery('#two').fadeTo(500, .5);
});
jQuery('#congrats').animate({
marginLeft: '+=1200px',
},
10000,
);
jQuery('#congrats').fadeOut(11000);
jQuery('#opacity').click(function() {
jQuery(this).addClass("faded");
});
});
</script>
</head>
<body>
<div id="one">
<p>This is the fadeToggle() method carrying out a "well-defined operation on data," the jQuery object ('#box'), in this case. The parameter is "500," which stands for half a second.</p>
</div>
<input type="submit" id="fadeToggle" value="fadeToggle()" />
<div id="two">
<p>This is the fadeTo() method.</p>
</div>
<input type="submit" id="fadeTo" value="fadeToggle()" />
<div id="heading">
<img id="congrats" src="congrats.gif" />
</div>
<img id="opacity" src="congrats.gif" />
</body>
</html>
那等于写了:
implementation "com.google.firebase:firebase-core:16.0.0"
这称为到if (x)
的上下文转换(请注意,它是直接初始化的,因此bool __flag(x);
if (__flag)
转换函数是一个候选方法)。
当我们针对bool
对该结构进行重载解析时,只有一个有效的候选者:explicit
。
但是当我们为m0
对该结构进行重载解析时,有两个:explicit operator bool() const
和m1
,因为explicit operator bool() const
可转换为operator double&&()
。后者是更好的匹配,因为double
转换函数具有额外的bool
限定,即使我们必须进行额外的const
转换也是如此。因此,它赢了。
只需从您的界面中删除bool
,因为此类型的意义不大。
答案 1 :(得分:1)
一旦T
可转换为bool
(double
is,std::pair
不可用),您的两个运算符就会匹配,并且您会得到一个模棱两可的呼叫,或者一个出于某种原因可能是更好的选择。
您应该只提供两个运算符之一,而不要同时提供。
答案 2 :(得分:1)
您的operator bool
和转换运算符在此设计中含糊不清。
在第一个上下文中,std::pair<int,int>
不会不强制转换为bool
因此使用显式布尔转换运算符。
在第二种情况下,double
确实被强制转换为bool
,因此T
使用转换运算符,该运算符返回double
,然后
隐式转换为bool
。
请注意,在第二种情况下,您正在调用std::move
,这会使value
处于有效但未定义的状态,当您将value
投射到double
时会导致未定义的行为在if
块中第二次。
我将使用命名成员函数来指示其是否有效,并修改转换运算符:
#include <algorithm>
#include <stdexcept>
template <typename T>
struct maybe {
maybe() : valid_(false) {}
maybe(T value) : valid_(true) { new (&value_) T(value); }
operator T&&() && { return std::move(value_); } // if rvalue
operator T&() & { return value_; } // if lvalue
operator const T&() const & { return value_; } // if const lvalue
bool valid() const { return valid_; }
T& value() {
if (!valid_) {
throw std::runtime_error("boom");
}
return value_;
}
private:
union {
T value_;
};
bool valid_;
};
int main() {
// fine, uses operator bool()
maybe<std::pair<int,int>> m0;
if (m0.valid()) {
std::pair<int,int> p = m0;
(void)p;
}
// throws error, uses operator T&&()
maybe<double> m1;
if (m1.valid()) {
double p = m1;
(void)p;
}
}
编辑:仅当value_
对象是右值引用时,转换运算符才应从成员maybe
中移出。在这种情况下,在函数签名后专门使用&&
-有关更多信息,请参见Kerrek SB's answer。