投射到 std::optional<T> 时,Clang 和 GCC 中的结果不同
Different results in Clang and GCC when casting to std::optional<T>
给定以下代码:
#include <iostream>
#include <optional>
struct foo
{
explicit operator std::optional<int>() {
return std::optional<int>( 1 );
}
explicit operator int() {
return 0;
}
};
int main()
{
foo my_foo;
std::optional<int> my_opt( my_foo );
std::cout << "value: " << my_opt.value() << std::endl;
}
gcc 7.2.0 writes value: 1
.
MSVC 2017 (15.3) 和 clang 4.0.0 however write value: 0
.
根据 C++ 标准,哪一个是正确的?
由于这是直接初始化,我们enumerate the constructors and just pick the best one. The relevant constructors for std::optional
是:
constexpr optional( const optional& other ); // (2)
constexpr optional( optional&& other ) noexcept(/* see below */); // (3)
template < class U = value_type >
/* EXPLICIT */ constexpr optional( U&& value ); // (8), with U = foo&
两者都是可行的((8)
仅在 int
可从 foo&
构造且 foo
既不是 std::in_place_t
也不是 [=18 时才参与重载决策=],所有这些都成立),但 (8)
是完全匹配,而 (2)
和 (3)
需要用户定义的转换,因此它应该是首选。 gcc在这里是错误的。
然而,gcc 实际上也没有调用 (3)
。它只是直接从 my_foo
转换为 optional<int>
的结果中初始化 my_opt
。这个带有 gcc 7.2 的程序打印 3
but none of 1a
, 1b
, or 2
:
#include <iostream>
template <class T>
struct opt {
opt() { }
opt(opt const& ) { std::cout << "1a\n"; }
opt(opt&& ) { std::cout << "1b\n"; }
template <class U>
opt(U&& ) { std::cout << "2\n"; }
};
struct foo
{
explicit operator opt<int>() { std::cout << "3\n"; return {}; }
};
int main()
{
opt<int> o(foo{});
}
我认为那不是一条允许的路线。我提交了 81952.
给定以下代码:
#include <iostream>
#include <optional>
struct foo
{
explicit operator std::optional<int>() {
return std::optional<int>( 1 );
}
explicit operator int() {
return 0;
}
};
int main()
{
foo my_foo;
std::optional<int> my_opt( my_foo );
std::cout << "value: " << my_opt.value() << std::endl;
}
gcc 7.2.0 writes value: 1
.
MSVC 2017 (15.3) 和 clang 4.0.0 however write value: 0
.
根据 C++ 标准,哪一个是正确的?
由于这是直接初始化,我们enumerate the constructors and just pick the best one. The relevant constructors for std::optional
是:
constexpr optional( const optional& other ); // (2)
constexpr optional( optional&& other ) noexcept(/* see below */); // (3)
template < class U = value_type >
/* EXPLICIT */ constexpr optional( U&& value ); // (8), with U = foo&
两者都是可行的((8)
仅在 int
可从 foo&
构造且 foo
既不是 std::in_place_t
也不是 [=18 时才参与重载决策=],所有这些都成立),但 (8)
是完全匹配,而 (2)
和 (3)
需要用户定义的转换,因此它应该是首选。 gcc在这里是错误的。
然而,gcc 实际上也没有调用 (3)
。它只是直接从 my_foo
转换为 optional<int>
的结果中初始化 my_opt
。这个带有 gcc 7.2 的程序打印 3
but none of 1a
, 1b
, or 2
:
#include <iostream>
template <class T>
struct opt {
opt() { }
opt(opt const& ) { std::cout << "1a\n"; }
opt(opt&& ) { std::cout << "1b\n"; }
template <class U>
opt(U&& ) { std::cout << "2\n"; }
};
struct foo
{
explicit operator opt<int>() { std::cout << "3\n"; return {}; }
};
int main()
{
opt<int> o(foo{});
}
我认为那不是一条允许的路线。我提交了 81952.