- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
考虑以下代码:
#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;
}
此代码无法编译,因为 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
) { /* ... */ }
或者类似的
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
) { /* ... */ }
它的缺点是 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{}};
}
你有两种类型 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
引入额外的模板构造函数来实现。 ( Live code demo at Coliru ):
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)}) {}
模板构造器直接匹配 C(U)
,因此明确优于 C(A)
和 C(B)
需要转换的构造函数。它被限制只接受类型 U
这样
U
可转换为 A
(出于显而易见的原因)U
不是 A
或引用 A
或派生自 A
的类型, 以避免与 C(const A&)
产生歧义U
情况下的构造函数和无限递归是例如A&
或 A&&
.值得注意的是,此解决方案不需要更改 T
的定义, A
, B
, C(A const&)
或 C(B const&)
, 所以它很好地独立。
关于c++ - 防止构造函数参数隐式转换为外部库类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21145035/
我是一名优秀的程序员,十分优秀!