您的测试集位于非现场链接,并且与您的原始帖子相比有所不同,因此我将逐字复制我在这里谈论的测试集:
static_assert(is_explicitly_convertible< double, double >::value, "1");
static_assert(is_explicitly_convertible< double &, double >::value, "2");
static_assert(is_explicitly_convertible< double const, double >::value, "3");
static_assert(is_explicitly_convertible< double const &, double >::value, "4");
static_assert(is_explicitly_convertible< double, double const & >::value, "5");
static_assert(is_explicitly_convertible< double &, double const & >::value, "6");
static_assert(is_explicitly_convertible< double const, double const & >::value, "7");
static_assert(is_explicitly_convertible< double const &, double const & >::value, "8");
static_assert(!is_explicitly_convertible< double, double & >::value, "9"); // not a ref
static_assert(is_explicitly_convertible< double &, double & >::value, "10");
static_assert(!is_explicitly_convertible< double const, double & >::value, "11");
static_assert(!is_explicitly_convertible< double const &, double & >::value, "12");
static_assert(is_explicitly_convertible< double, double const >::value, "13");
static_assert(is_explicitly_convertible< double &, double const >::value, "14");
static_assert(is_explicitly_convertible< double const, double const >::value, "15");
static_assert(is_explicitly_convertible< double const &, double const >::value, "16");
static_assert(is_explicitly_convertible< AA const &, A const & >::value, "=&1.a");
static_assert(is_explicitly_convertible< CC const &, C const & >::value, "=&1.b");
static_assert(is_explicitly_convertible< BB const &, B const & >::value, "=&1.c");
static_assert(!is_explicitly_convertible< AA const &, A & >::value, "&1.a");
static_assert(!is_explicitly_convertible< CC const &, C & >::value, "&1.b");
static_assert(!is_explicitly_convertible< BB const &, B & >::value, "&1.c");
static_assert(is_explicitly_convertible< AA const, A const & >::value, "=1.a");
static_assert(is_explicitly_convertible< CC const, C const & >::value, "=1.b");
static_assert(is_explicitly_convertible< BB const, B const & >::value, "=1.c");
//static_assert(!is_explicitly_convertible< AA const, A >::value, "=2.a"); // ???????????????
//static_assert(!is_explicitly_convertible< CC const, C >::value, "=2.b");
//static_assert(!is_explicitly_convertible< BB const, B >::value, "=2.c");
static_assert(!is_explicitly_convertible< AA const, A & >::value, "=3.a"); // good!
static_assert(!is_explicitly_convertible< CC const, C & >::value, "=3.b"); //
static_assert(!is_explicitly_convertible< BB const, B & >::value, "=3.c"); //
static_assert(!is_explicitly_convertible< AA const, A && >::value, "=4.a"); // not interesting
static_assert(!is_explicitly_convertible< CC const, C && >::value, "=4.b"); //
static_assert(!is_explicitly_convertible< BB const, B && >::value, "=4.c"); //
static_assert(!is_explicitly_convertible< AA const, B const & >::value, "=5.a");
static_assert(!is_explicitly_convertible< AA const, C const & >::value, "=5.b");
static_assert(!is_explicitly_convertible< BB const, A const & >::value, "=5.c");
static_assert(!is_explicitly_convertible< BB const, C const & >::value, "=6.a");
static_assert(!is_explicitly_convertible< CC const, A const & >::value, "=6.b");
static_assert(!is_explicitly_convertible< CC const, B const & >::value, "=6.c");
static_assert(!is_explicitly_convertible< AA const, B & >::value, "=7.a");
static_assert(!is_explicitly_convertible< AA const, C & >::value, "=7.b");
static_assert(!is_explicitly_convertible< BB const, A & >::value, "=7.c");
static_assert(!is_explicitly_convertible< BB const, C & >::value, "=8.a");
static_assert(!is_explicitly_convertible< CC const, A & >::value, "=8.b");
static_assert(!is_explicitly_convertible< CC const, B & >::value, "=8.c");
static_assert(!is_explicitly_convertible< AA const, B >::value, "=9.a"); // very subtle moment (see class AA above)
static_assert(!is_explicitly_convertible< AA const, C >::value, "=9.b");
static_assert(is_explicitly_convertible< BB const, A >::value == std::is_constructible< A, A && >::value, "=9.c"); // (see class BB above)
static_assert(!is_explicitly_convertible< BB const, C >::value, "=10.a");
static_assert(!is_explicitly_convertible< CC const, A >::value, "=10.b");
static_assert(!is_explicitly_convertible< CC const, B >::value, "=10.c");
static_assert(is_explicitly_convertible< AA, A & >::value, "~1.a");
static_assert(is_explicitly_convertible< CC, C & >::value, "~1.b");
static_assert(is_explicitly_convertible< BB, B & >::value, "~1.c");
//static_assert(!is_explicitly_convertible< AA, A >::value, "~2.a"); // ???????????????
//static_assert(!is_explicitly_convertible< CC, C >::value, "~2.b");
//static_assert(!is_explicitly_convertible< BB, B >::value, "~2.c");
static_assert(is_explicitly_convertible< AA, A const & >::value, "~3.a"); // convertible
static_assert(is_explicitly_convertible< CC, C const & >::value, "~3.b"); //
static_assert(is_explicitly_convertible< BB, B const & >::value, "~3.c"); //
static_assert(!is_explicitly_convertible< AA, B const & >::value, "~4.a");
static_assert(!is_explicitly_convertible< AA, C const & >::value, "~4.b");
static_assert(!is_explicitly_convertible< BB, A const & >::value, "~4.c");
static_assert(!is_explicitly_convertible< BB, C const & >::value, "~5.a");
static_assert(!is_explicitly_convertible< CC, A const & >::value, "~5.b");
static_assert(!is_explicitly_convertible< CC, B const & >::value, "~5.c");
static_assert(std::is_convertible< double, double const & >::value, "5*");
static_assert(!std::is_convertible< double, double & >::value, "9*");
如果您使用 gcc 4.7.2(可能更早,我还没有检查过),那么 C++11 标准库可以解决问题:
std::is_explicitly_convertible<From,To>
定义在<type_traits>
但是,您将利用该版本的 C++11 标准库中的错误。该特征模板不应该存在,因为它已根据N3047 (2010) 从标准中删除。
如果你正在使用 gcc 4.8.1(或者可能是 4.8;我还没有检查过),那么这个特性不再在库中,如果你想要它,你必须再次推出你自己的特性。
但是首先检查 gcc 4.7.2 中的定义只是人类的<type_traits>
行为,这样做表明 GNU 实现者认为该特征只不过是 的倒数std::is_constructible<To,From>
:
/// is_explicitly_convertible
template<typename _From, typename _To>
struct is_explicitly_convertible
: public is_constructible<_To, _From>
{ };
人们可能会想:当然。
那为什么不继续下去呢?N3047 解释:
剩下的问题是,is_explicitly_convertible
应该以哪种方式修复同样受影响的特征。基本选择是:
- 通过返回当前的 static_cast 表达式进行修复
is_explicitly_convertible
,不再is_explicitly_convertible
依赖is_constructible
.
is_explicitly_convertible
从标准中删除。
考虑了第一个选择,但事实证明,对于“显式可转换”的实际含义存在完全不同的理解。虽然有些人认为static_cast
正确地表达了这一点,但其他人认为固定is_constructible
也可以提供更好的含义is_explicitly_convertible
。因此本文建议is_explicitly_convertible
从工作草案中删除。现在这应该没有什么害处,因为还没有任何东西依赖于那个特殊的定义。如果事实证明这个特征仍然有用,它可以在标准的另一个修订版中添加。
该定义中没有已知的错误,但对于它编纂的“明确可转换”的含义是否正确存在反对意见:-
- D1)
From
可显式转换为To
=dfTo
可从From
- D2)
From
可以显式转换为To
=dfFrom
可以静态转换为To
我不会争论这个争议(我什至还没有弄清楚有什么区别,我自己)但会建议你付钱并做出选择。
如果您喜欢 D1),那么您可以简单地从 gcc 4.7.2 中获取特征的定义<type_traits>
,如上所述。
如果你喜欢 D2,那么你可以抄袭和改编std::is_convertible<From,To>
来自 gcc 4.8.1的定义<type_traits>
。此定义调用您必须跟踪的内部辅助函数。您想要的调整是更改 SFINAE 测试 for From
can be 隐式转换
To
为 test for From
can be static_cast
toTo
; 这意味着更换:
template<typename _From1, typename _To1>
static decltype(__test_aux<_To1>(std::declval<_From1>()), __one())
__test(int);
和:
template<typename _From1, typename _To1>
static decltype(__test_aux<_To1>(static_cast<_To1>(std::declval<_From1>())), __one())
__test(int);
此定义的简化版本(忽略诸如作为函数或数组类型之类的情况
From
)void
适用To
于您static_assert
的 s 中测试的类型:
template<typename From, typename To>
struct is_explicitly_convertible
{
template<typename T>
static void f(T);
template<typename F, typename T>
static constexpr auto test(int) ->
decltype(f(static_cast<T>(std::declval<F>())),true) {
return true;
}
template<typename F, typename T>
static constexpr auto test(...) -> bool {
return false;
}
static bool const value = test<From,To>(0);
};
D1 定义或缩减的 D2 定义都支持您的所有 63 个static_assert
s。(我用 g++ 4.7.2 和 4.8.1 编译-g;-O0;-Wall;-std=c++11
,以及-std=gnu++1y
你使用的那个)
您的最新解决方案表明您已经通过自己的方式进入了 D2 学校,并采用了不同的实施方式。
在这两者中,在我发现它有问题之前,我更喜欢 D1 定义,根据 gcc 4.7.2,仅仅因为它是最简单的,特别是
std::is_constructible
.