Dav*_*man 6 c++ constructor boost implicit-conversion c++11
请考虑以下代码:
#include <boost/range.hpp>
#include <boost/iterator/counting_iterator.hpp>
typedef boost::iterator_range<boost::counting_iterator<int>> int_range;
template <typename T>
class Ref {
T* p_;
public:
Ref(T* p) : p_(p) { }
/* possibly other implicit conversion constructors,
but no unconstrained template constructors that don't
use the explicit keyword... */
operator T*() const { return p_; }
operator const T*() const { return p_; }
};
struct Bar { };
class Foo {
public:
Foo(int a, char b) { /* ... */ }
Foo(int a, const Ref<Bar>& b) { /* ... */ }
Foo(int a, const int_range& r) { /* ... */ }
};
int main() {
Bar b;
Foo f(5, &b);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这段代码不能编译,因为Foo构造函数的使用是模糊的,因为它boost::iterator_range显然有一个模板化的构造函数,它接受一个参数并且没有被声明为explicit.假设改变结构Ref不是一个选项,我该如何解决这个问题呢?我提出了以下可能的解决方案,但它很难看并且不易维护,特别是如果有多个构造函数Foo:
template<typename range_like>
Foo(
int a,
const range_like& r,
typename std::enable_if<
not std::is_convertible<range_like, Ref<Bar>>::value
and std::is_convertible<range_like, int_range>::value,
bool
>::type unused = false
) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
或类似的
template<typename range_like>
Foo(
int a,
const range_like& r,
typename std::enable_if<
std::is_same<typename std::decay<range_like>::type, int_range>::value,
bool
>::type unused = false
) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
它的缺点是所有其他隐式类型转换都int_range被禁用,因此依赖于未指定的特征boost(而且我的直觉告诉我,这可能是一个坏主意).有一个更好的方法吗?(除了C++ 14"概念 - 精简版",这就是我认为这个问题的真正原因).
我认为这个程序是你问题的一个最小例子:
#include <iostream>
struct T {};
struct A {
A(T) {}
};
struct B {
B(T) {}
};
struct C {
C(A const&) { std::cout << "C(A)\n"; }
C(B const&) { std::cout << "C(B)\n"; }
};
int main() {
C c{T{}};
}
Run Code Online (Sandbox Code Playgroud)
您有两种类型A,B它们都可以从另T一种类型C隐式转换,另一种类型可以从A和隐式转换B,但是隐式转换T是不明确的.你渴望消除歧义的情况,以便C为隐式转换T使用转换序列T => A => C,但你必须在不改变的定义,这样做A和B.
显而易见的解决方案 - 已经在评论中提出 - 是为了引入第三个转换构造函数C:C(T value) : C(A(value)) {}.你已经拒绝了这个解决方案,因为它不够通用,但没有说明"一般"问题是什么.
我猜想你想要解决的更普遍的问题是C从任何U可隐式转换为A使用转换序列的类型中明确地隐式转换U => A => C.这可以通过引入一个额外的模板构造函数来实现C(Coliru的Live代码演示):
template <typename U, typename=typename std::enable_if<
!std::is_base_of<A,typename std::decay<U>::type>::value &&
std::is_convertible<U&&, A>::value>::type>
C(U&& u) : C(A{std::forward<U>(u)}) {}
Run Code Online (Sandbox Code Playgroud)
模板的构造是一个直接匹配C(U),因此明确地优于C(A)和C(B)这将需要一个转换构造.它仅限于接受U这样的类型
U是可转换的A(出于显而易见的原因)U为了避免与构造函数的歧义和在例如或的情况下的无限递归,它不是 A或者是对它的引用A或类型.AC(const A&)UA&A&&值得注意的是该解决方案不需要改变的定义T,A,B,C(A const&)或者C(B const&),因此它是很好的自足.
| 归档时间: |
|
| 查看次数: |
687 次 |
| 最近记录: |