如何确定(在<type_traits>精神上)一种类型是否可以明确转换为另一种类型?例如,我想检查F::explicit operator double const & () const;某些class/ 的存在struct F,但同时,F不应该明确地转换为float或long double(类似pred< double const & >::value && !pred< float >::value && !pred< long double >::value).
注意,std::is_convertible< From, To >::value检查"是否可以使用隐式转换将From转换为To ".但我想确定是否有显式转换运算符.
而且,如果可能的话,"如何确定,类型从可转换为一个,即参考键入要?"?
And*_*zej 14
你需要定义自己的:
template <class U, class T>
struct is_explicitly_convertible
{
enum {value = std::is_constructible<T, U>::value && !std::is_convertible<U, T>::value};
};
Run Code Online (Sandbox Code Playgroud)
你的测试集是在一个异地链接,并且自你的原始帖子以来有所不同,所以我将逐字复制我在这里讨论的测试集:
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*");
Run Code Online (Sandbox Code Playgroud)
如果您使用gcc 4.7.2(可能更早,我还没有检查过),那么C++ 11标准库解决了这个问题:
std::is_explicitly_convertible<From,To>
Run Code Online (Sandbox Code Playgroud)
定义于 <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>
{ };
Run Code Online (Sandbox Code Playgroud)
人们可能会想:但当然.
那么为什么不继续这样做呢?N3047解释说:
剩下的问题是,应该以何种方式
is_explicitly_convertible修复受影响的特性.基本选择是:
is_explicitly_convertible通过返回当前的static_cast表达式进行修复,不再is_explicitly_convertible依赖于is_constructible.is_explicitly_convertible从标准中删除.考虑了第一个选择,但事实证明,对于"明确可兑换"实际应该意味着什么存在完全不同的理解.虽然有些人认为
static_cast正确地表达了这一点,但其他人认为修正案is_constructible也会提供更好的意义is_explicitly_convertible.因此,本文建议is_explicitly_convertible从工作草案中删除.现在这应该没有坏处,因为还没有任何东西依赖于那个特殊的定义.如果事实证明,特性仍然有用,它可以添加到标准的另一个版本中.
该定义中没有已知的错误,但是对于它编纂的"明确可兑换"的含义是否正确的观点存在反对意见: -
From明确可转换为To= df To是可构造的FromFrom明确可转换为To= df From可以静态转换为To我不会争论这个争议(我甚至没有弄清楚差异是什么,我自己)但是会建议你付钱并做出你的选择.
如果您喜欢D1),那么您可以简单地从gcc 4.7.2中获取特征的定义<type_traits>,如上所述.
如果您喜欢D2,那么您可以抄袭并调整std::is_convertible<From,To>
gcc 4.8.1 的定义<type_traits>.此定义调用您必须跟踪的内部辅助功能.你想适应将改变SFINAE测试From可以隐式转换
To到测试From可static_cast到To ; 这意味着要取代:
template<typename _From1, typename _To1>
static decltype(__test_aux<_To1>(std::declval<_From1>()), __one())
__test(int);
Run Code Online (Sandbox Code Playgroud)
有:
template<typename _From1, typename _To1>
static decltype(__test_aux<_To1>(static_cast<_To1>(std::declval<_From1>())), __one())
__test(int);
Run Code Online (Sandbox Code Playgroud)
该定义的简化版本(忽略这种情况下为
From是void和To作为一个功能或阵列型),这将对于在您的测试的类型做static_assertS:
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);
};
Run Code Online (Sandbox Code Playgroud)
D1定义或缩减D2定义都支持你static_assert的所有63个.(我用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.