gpt4 book ai didi

c++ - 防止构造函数参数隐式转换为外部库类型

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:27:35 25 4
gpt4 key购买 nike

考虑以下代码:

#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{}};
}

你有两种类型 AB都可以从另一种类型隐式转换 T , 和另一种 CA 隐式转换和 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com