不调用initializer_list构造函数的情况下将不可复制,不可移动类型构建为函数参数

8
#include <initializer_list>
#include <iostream>

namespace {

class C {
public:
    C(C const &) = delete;
    C(C &&) = delete;
    C(int) {
        std::cout << "int\n";
    }
    C(std::initializer_list<int>) {
        std::cout << "initializer\n";
    }
};

void f(C) {
}

// Compiles and prints "initializer" when called
C g() { return {0}; }
// Fails to compile
// C h() { return 0; }

}   // namespace

int main() {
    // Compiles and prints "initializer"
    f({0});
    // Fails to compile
    // f(0);
}

是否可以在不调用initializer_list构造函数的情况下,将C构造为不可复制、不可移动的类型,作为函数参数或函数返回值?


我看不到有什么方法可以做到这一点(这也是在类内初始化器中的一个问题:struct A { std::vector<int> x{2}; }。你不能将 x 初始化为大小为 2。也不能说 = 2,因为构造函数是显式的)。 - Johannes Schaub - litb
1
你正在传递一个非可复制等类型的对象的副本。为什么?这没有意义。 - deviantfan
1
@deviantfan:我正在尝试直接在原地构建对象。 - David Stone
@JohannesSchaub-litb,你能不能直接说struct A { vector<int> x = vector<int>(2); };?我现在无法测试它,因为GCC 4.6不支持类内初始化器。 - Adam H. Peterson
@DavidStone,我不相信你能做到。如果在花括号初始化中匹配到initializer_list构造函数,则它将优先于非initializer_list构造函数,并且我无法想出一种方法使花括号初始化与int构造函数匹配,但不与initializer_list匹配。我能想到的所有其他构造C的方法都涉及传递给函数或从函数返回时的(名义上的)临时对象,而这与不可复制、不可移动的类不兼容。 - Adam H. Peterson
显示剩余2条评论
1个回答

2

只有当你能够更改C,使得期望的构造函数可以被选择而不是初始化列表构造函数时,才有可能实现。例如,通过将参数类型包装在某些不能转换为初始化列表构造函数元素类型的东西中:

#include <initializer_list>
#include <iostream>

namespace {

template<class T>
struct wrap
{
  T value;
};

class C {
public:
    C(C const &) = delete;
    C(C &&) = delete;
    C(wrap<int>) {
        std::cout << "int\n";
    }
    C(std::initializer_list<int>) {
        std::cout << "initializer\n";
    }
};

void f(C) {
}

// Compiles and prints "int" when called
C g() { return {wrap<int>{0}}; }

}   // namespace

int main() {
    // Compiles and prints "int"
    f({wrap<int>{0}});
    g();
}

这将打印:

int
int

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接