`std::common_type` 是关联的吗?
Is `std::common_type` associative?
模板class std::common_type
将通用类型计算为可变类型列表。 It is defined using the return type of the ternary operator x:y?z
recursively. 根据该定义,计算 std::common_type<X,Y>
是否具有关联性对我来说并不明显,即。 e.是否
using namespace std;
static_assert( is_same<common_type< X, common_type<Y,Z>::type >::type,
common_type< common_type<X,Y>::type, Z >::type>::value, "" );
对于 is_same<...>
表达式有效的所有类型 X
、Y
和 Z
, 永远不会抛出编译时错误。
请注意,我不是在问
static_assert( is_same<common_type<X,Y>::type,
common_type<Y,X>::type>::value, "" );
永远火。显然不会。以上是一个完全不同的问题。
另请注意,std::common_type
的规范在 C++14 中略有更改,并且可能会在 C++17 中再次更改。所以对于不同版本的标准,答案可能不同。
#include <type_traits>
struct T2;
struct T1 {
T1(){}
T1(int){}
operator T2();
};
struct T2 {
operator int() { return 0; }
};
struct T3 {
operator int() { return 0; }
};
T1::operator T2() { return T2(); }
using namespace std;
using X = T1;
using Y = T2;
using Z = T3;
int main()
{
true?T2():T3(); // int
static_assert(std::is_same<std::common_type_t<T2,
T3>,
int>::value,
"Not int");
true?T1():(true?T2():T3()); // T1
static_assert(std::is_same<std::common_type_t<T1,
std::common_type_t<T2,
T3>>,
T1>::value,
"Not T1");
// -----------------------------------------
true?T1():T2(); // T2
static_assert(std::is_same<std::common_type_t<T1,
T2>,
T2>::value,
"Not T2");
true?(true?T1():T2()):T3(); // int
static_assert(std::is_same<std::common_type_t<std::common_type_t<T1,
T2>,
T3>,
int>::value,
"Not int");
// -----------------------------------------
static_assert( is_same<common_type_t< X, common_type_t<Y,Z> >,
common_type_t< common_type_t<X,Y>, Z > >::value,
"Don't match");
}
哎呀!这里的心理体操伤了我的头,但我想出了一个无法编译的案例,打印 "Don't match",gcc 4.9.2 和 "C++14" (gcc 5.1) on ideone。现在是否符合是另一回事...
现在声明适用于 class 类型,std::common_type_t<X, Y>
应该是 X
或 Y
,但我已强制 std::common_type_t<T2, T3>
转换为 int
.
请尝试使用其他编译器,让我知道会发生什么!
这在 MinGW-w64(gcc 4.9.1) 上失败。在 VS2013 和(感谢 Baum mit Augen)在 gcc5.2 或带有 libc++ 的 clang 3.7 上也失败。
#include <type_traits>
using namespace std;
struct Z;
struct X{operator Z();};
struct Y{operator X();};
struct Z{operator Y();};
static_assert( is_same<common_type<X,Y>::type,
common_type<Y,X>::type>::value, "" ); // PASS
static_assert( is_same<common_type<X,Z>::type,
common_type<Z,X>::type>::value, "" ); // PASS
static_assert( is_same<common_type<Y,Z>::type,
common_type<Z,Y>::type>::value, "" ); // PASS
static_assert( is_same<common_type< X, common_type<Y,Z>::type >::type,
common_type< common_type<X,Y>::type, Z >::type>::value, "" ); // FAIL...
这不是关联!这是一个失败的程序:
#include <type_traits>
struct Z;
struct X { X(Z); }; // enables conversion from Z to X
struct Y { Y(X); }; // enables conversion from X to Y
struct Z { Z(Y); }; // enables conversion from Y to Z
using namespace std;
static_assert( is_same<common_type< X, common_type<Y,Z>::type >::type,
common_type< common_type<X,Y>::type, Z >::type>::value,
"std::common_type is not associative." );
思路很简单:下图显示,common_type
计算的内容:
X,Y -> Y
Y,Z -> Z
X,Z -> X
第一行是合乎逻辑的,因为 X
可以转换为 Y
,但反之则不行。其他两条线也一样。一旦 X
和 Y
组合并与 Z
重新组合,我们得到 Z
。另一方面,组合 Y
和 Z
并将 X
与结果组合得到 X
。因此结果不同。
这成为可能的根本原因是可转换性不是传递性的,即。 e.如果 X
可转换为 Y
且 Y
可转换为 Z
,则不表示 X
可转换为 Z
。如果可转换性是可传递的,那么转换将双向进行,因此 common_type
无法明确计算并导致编译时错误。
这个推理独立于标准版本。它适用于 C++11、C++14 和即将推出的 C++17。
模板class std::common_type
将通用类型计算为可变类型列表。 It is defined using the return type of the ternary operator x:y?z
recursively. 根据该定义,计算 std::common_type<X,Y>
是否具有关联性对我来说并不明显,即。 e.是否
using namespace std;
static_assert( is_same<common_type< X, common_type<Y,Z>::type >::type,
common_type< common_type<X,Y>::type, Z >::type>::value, "" );
对于 is_same<...>
表达式有效的所有类型 X
、Y
和 Z
,永远不会抛出编译时错误。
请注意,我不是在问
static_assert( is_same<common_type<X,Y>::type,
common_type<Y,X>::type>::value, "" );
永远火。显然不会。以上是一个完全不同的问题。
另请注意,std::common_type
的规范在 C++14 中略有更改,并且可能会在 C++17 中再次更改。所以对于不同版本的标准,答案可能不同。
#include <type_traits>
struct T2;
struct T1 {
T1(){}
T1(int){}
operator T2();
};
struct T2 {
operator int() { return 0; }
};
struct T3 {
operator int() { return 0; }
};
T1::operator T2() { return T2(); }
using namespace std;
using X = T1;
using Y = T2;
using Z = T3;
int main()
{
true?T2():T3(); // int
static_assert(std::is_same<std::common_type_t<T2,
T3>,
int>::value,
"Not int");
true?T1():(true?T2():T3()); // T1
static_assert(std::is_same<std::common_type_t<T1,
std::common_type_t<T2,
T3>>,
T1>::value,
"Not T1");
// -----------------------------------------
true?T1():T2(); // T2
static_assert(std::is_same<std::common_type_t<T1,
T2>,
T2>::value,
"Not T2");
true?(true?T1():T2()):T3(); // int
static_assert(std::is_same<std::common_type_t<std::common_type_t<T1,
T2>,
T3>,
int>::value,
"Not int");
// -----------------------------------------
static_assert( is_same<common_type_t< X, common_type_t<Y,Z> >,
common_type_t< common_type_t<X,Y>, Z > >::value,
"Don't match");
}
哎呀!这里的心理体操伤了我的头,但我想出了一个无法编译的案例,打印 "Don't match",gcc 4.9.2 和 "C++14" (gcc 5.1) on ideone。现在是否符合是另一回事...
现在声明适用于 class 类型,std::common_type_t<X, Y>
应该是 X
或 Y
,但我已强制 std::common_type_t<T2, T3>
转换为 int
.
请尝试使用其他编译器,让我知道会发生什么!
这在 MinGW-w64(gcc 4.9.1) 上失败。在 VS2013 和(感谢 Baum mit Augen)在 gcc5.2 或带有 libc++ 的 clang 3.7 上也失败。
#include <type_traits>
using namespace std;
struct Z;
struct X{operator Z();};
struct Y{operator X();};
struct Z{operator Y();};
static_assert( is_same<common_type<X,Y>::type,
common_type<Y,X>::type>::value, "" ); // PASS
static_assert( is_same<common_type<X,Z>::type,
common_type<Z,X>::type>::value, "" ); // PASS
static_assert( is_same<common_type<Y,Z>::type,
common_type<Z,Y>::type>::value, "" ); // PASS
static_assert( is_same<common_type< X, common_type<Y,Z>::type >::type,
common_type< common_type<X,Y>::type, Z >::type>::value, "" ); // FAIL...
这不是关联!这是一个失败的程序:
#include <type_traits>
struct Z;
struct X { X(Z); }; // enables conversion from Z to X
struct Y { Y(X); }; // enables conversion from X to Y
struct Z { Z(Y); }; // enables conversion from Y to Z
using namespace std;
static_assert( is_same<common_type< X, common_type<Y,Z>::type >::type,
common_type< common_type<X,Y>::type, Z >::type>::value,
"std::common_type is not associative." );
思路很简单:下图显示,common_type
计算的内容:
X,Y -> Y
Y,Z -> Z
X,Z -> X
第一行是合乎逻辑的,因为 X
可以转换为 Y
,但反之则不行。其他两条线也一样。一旦 X
和 Y
组合并与 Z
重新组合,我们得到 Z
。另一方面,组合 Y
和 Z
并将 X
与结果组合得到 X
。因此结果不同。
这成为可能的根本原因是可转换性不是传递性的,即。 e.如果 X
可转换为 Y
且 Y
可转换为 Z
,则不表示 X
可转换为 Z
。如果可转换性是可传递的,那么转换将双向进行,因此 common_type
无法明确计算并导致编译时错误。
这个推理独立于标准版本。它适用于 C++11、C++14 和即将推出的 C++17。