1

考虑遵循二叉树,其中节点有两个儿子或带有标签的叶子。此代码在 g++ 4.7.2 中编译:

#include <memory>
using namespace std;

struct Tree {
    unique_ptr<Tree> left, right;
    char label;

    Tree(char label) : label(label) {}

    Tree(Tree && left, Tree && right) :
        left(new Tree(move(left))), 
        right(new Tree(move(right))) {}

    //~ explicit Tree(Tree && left, bool right) {}

} tree {{1, 2}, 3};

当我取消注释显式构造函数时,它无法编译(如果这个显式构造函数是私有的,它也会失败)。这是 gcc 错误,还是显式构造函数禁止对具有相同数量参数的非显式构造函数使用初始化列表构造?

编辑:s/隐式/非显式/。抱歉,我使用“隐式”一词表示“允许隐式转换”,而“显式”一词则表示“用关键字显式标记”。我将编译器自动生成的构造函数称为“默认”,所以我没有注意到“隐式”这个词会如此模棱两可。

4

2 回答 2

4

你的问题似乎假设了一些不正确的东西,并揭示了一个基本的误解。

首先,隐式生成的构造函数在“使用初始化列表时”不会隐藏。每当您定义构造函数时,无论您是否将其标记为,它们的生成都会被简单地禁止explicit

但请注意:“隐式”构造函数通常是指当您不提供时由编译器隐式(自动)生成的构造函数,而不是缺少explicit修饰符的构造函数。在上一段中,我谈论的是前者,但我被引导相信您正在考虑后者。

假设是这种情况,那么无论您是否使用初始化列表,未标记为构造函数都不会被标记为explicit的构造函数隐藏。explicit

您的程序无法编译的原因是您的explicit构造函数恰好比非构造函数更匹配explicit,因为它接受 abool作为其第二个参数,它只需要标准转换来匹配参数2。另一方面,explicit接受 a 的非构造函数Tree&&需要用户定义的转换,其中涉及临时Tree对象的构造,并且标准转换优于用户定义的转换。

要强制编译器Tree从参数构造一个临时变量2而不是转换2为 a bool(因此,调用非explicit构造函数),您必须通过将构造函数调用更改为以下内容来指定它:

struct Tree
{
    ...
} tree {{1, Tree(2)}, 3}; // Explicitly specify the second argument is to be
                          // used to create a temporary Tree object, rather
                          // than being converted to a bool

另请注意,虽然这同样适用于顶级树的创建(即也3被转换为 abool并且您的explicit构造函数被再次调用),但在这种情况下这不是问题,因为您正在直接初始化tree对象,并且不尝试隐式转换。

于 2013-02-16T18:45:41.243 回答
0

您的问题的解决方案可能是:

template<
  typename Bool,
  typename=typename std::enable_if<
    std::is_same<
      typename std::decay<Bool>::type,
      bool
    >
  >::type
>
explicit Tree(Tree && left, Bool&& right) {}

我已经阻止了任何类型的转换,而不是bool作为第二个参数传递的变体。

但是,您最好创建一个静态方法来执行此构造函数想要做的事情,而不是在问题上抛出更多重载的构造函数。

于 2013-02-16T19:24:11.397 回答