“std::common_type”是关联性的
Is `std::common_type` associative?
模板类std::common_type
计算可变参数类型列表的通用类型。它是使用三元运算符的返回类型x:y?z
递归定义的。从这个定义来看,计算std::common_type<X,Y>
是否具有关联性,即是否具有关联性,即计算是否
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 中再次更改。因此,对于不同版本的标准,答案可能会有所不同。
在MinGW-w64(gcc 4.9.1(上失败。在VS2013和(感谢Baum mit Augen(在gcc5.2或clang 3.7上使用libc ++上也失败。
#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 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");
}
哎哟!这里的心理体操让我头疼,但我想出了一个无法编译的案例,在 ideone 上打印了"不匹配",带有 gcc 4.9.2 和"C++14"(gcc 5.1(。现在这是否合规是另一回事......
现在声明是针对类类型的,std::common_type_t<X, Y>
应该是X
或Y
,但我强迫std::common_type_t<T2, T3>
转换为int
。
请尝试使用其他编译器,让我知道会发生什么!
这不是关联性的!这是一个失败的程序:
#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
。因此,结果是不同的。
这成为可能的根本原因是可兑换性不是可传递的,即如果X
可转换为Y
并且Y
可转换为Z
则并不意味着X
可转换为Z
。如果可转换性是可传递的,那么转换将双向工作,因此无法明确计算common_type
并导致编译时错误。
此推理独立于标准版本。它适用于C++11、C++14和即将到来的C++17。
- 使用std::multimap迭代器创建std::list
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如何导出包含具有"std::unique_ptr"值的"std::map"属性的
- 从持续时间构造std::chrono::system_clock::time_point
- std::具有相同基类的类的变体
- std::向量与传递值的动态数组
- 使用std::vector的OpenCL矩阵乘法
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- std::condition_variable::wait()如何评估给定的谓词
- 如何获取std::result_of函数的返回类型
- std::原子加载和存储都需要吗
- 将对象移动到std::shared_ptr
- POCO::PostgreSQL:如何将std::vector支持添加到`Binder::bind`
- 使用一个考虑到std::map中键值的滚动或换行的键
- 如何从 std::atomic 中提取指针 T<T>?
- 为什么 std::unique 不调用 std::sort?
- 使用std::函数映射对象方法
- “std::common_type”是关联性的