yur*_*hek 15 c++ sfinae type-traits implicit-conversion c++11
假设我std::is_convertible无论出于何种原因并且想要自己实现它.该标准说明了以下几点:
is_convertible<From, To>当且仅当以下代码中的返回表达式格式正确时,才应满足模板特化的谓词条件,包括对函数返回类型的任何隐式转换:Run Code Online (Sandbox Code Playgroud)To f() { return declval<From>(); }
好吧,没什么大不了的,我可以这样做(注意参数顺序与之相反std::is_convertible,这是故意的,与问题无关):
template <typename To_, typename From_>
class my_is_convertible {
private:
template <typename To>
struct indirector {
indirector(To);
};
template <typename To, typename From>
struct tag {};
template <typename To, typename From>
static auto test(tag<To, From>)
-> decltype(indirector<To>(std::declval<From>()), std::true_type());
static auto test(...)
-> std::false_type;
public:
static constexpr bool value = decltype(test(tag<To_, From_>()))::value;
};
Run Code Online (Sandbox Code Playgroud)
这似乎按预期工作,据我所知,同样的事情.
现在我可以区分隐式和显式(或根本没有)构造函数:
struct A {};
struct B {};
struct Test {
Test(A);
explicit Test(B);
};
int main() {
std::cout << my_is_convertible<Test, A>::value; // true
std::cout << my_is_convertible<Test, B>::value; // false
return 0;
}
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.现在,我想对多个参数构造函数做同样的事情.这之前没有意义,c++11因为没有办法隐式调用multiargument构造函数.但是现在我们有了大括号括起来的初始化列表语法,而explicitmultiargument构造函数上的关键字也有所不同.
让我们扩展定义:
my_is_convertible_many<To, From...>当且仅当以下代码中的返回表达式格式正确时,才应满足模板特化的谓词条件,包括对函数返回类型的任何隐式转换:Run Code Online (Sandbox Code Playgroud)To f() { return {declval<From>()...}; }
为了实现它,我采取了明显的方式:
template <typename To_, typename... From_>
class my_is_convertible_many {
private:
template <typename To>
struct indirector {
indirector(To);
};
template <typename To, typename... From>
struct tag {};
template <typename To, typename... From>
static auto test(tag<To, From...>)
-> decltype(indirector<To>({std::declval<From>()...}), std::true_type());
static auto test(...)
-> std::false_type;
public:
static constexpr bool value = decltype(test(tag<To_, From_...>()))::value;
};
Run Code Online (Sandbox Code Playgroud)
这正确地报告true存在匹配的隐式构造函数,false如果不是matcing构造函数.但如果有一个明确的匹配构造函数(至少在gcc 4.8.1上),它就无法编译:
struct A {};
struct B {};
struct C {};
struct Test {
Test(A, A);
//Test(B, B);
explicit Test(C, C);
};
int main() {
std::cout << my_is_convertible_many<Test, A, A>::value; // true, correct
std::cout << my_is_convertible_many<Test, B, B>::value; // false, correct
std::cout << my_is_convertible_many<Test, C, C>::value; // error
return 0;
}
Run Code Online (Sandbox Code Playgroud)
错误是关于尝试隐式调用显式构造函数,在gcc上听起来像这样:
main.cpp: In substitution of 'template<class To, class ... From> static decltype (((my_is_convertible_many<To_, From_>::indirector<To>)({(declval<From>)()...}), std::true_type())) my_is_convertible_many<To_, From_>::test(my_is_convertible_many<To_, From_>::tag<To, From ...>) [with To = To; From = {From ...}; To_ = Test; From_ = {C, C}] [with To = Test; From = {C, C}]':
main.cpp:21:73: required from 'constexpr const bool my_is_convertible_many<Test, C, C>::value'
main.cpp:37:54: required from here
main.cpp:17:97: error: converting to 'Test' from initializer list would use explicit constructor 'Test::Test(C, C)'
static auto test(tag<To, From...>) -> decltype(indirector<To>({std::declval<From>()...}), std::true_type());
^
Run Code Online (Sandbox Code Playgroud)
这是明智的.但是,我希望这种过载test能够解决,而另一种则需要使用,因此不会产生错误.
所以问题是:为什么不发生这种情况,我能做些什么呢?
| 归档时间: |
|
| 查看次数: |
532 次 |
| 最近记录: |