定义一个没有默认可构造数据成员的空默认构造函数

时间:2015-10-24 15:08:24

标签: c++ c++11 default-constructor regular-type

考虑以下示例:

class MyWrapper {
    public:
        MyWrapper() {};
    private:
       ThirdPartyLibraryType impl;
};

假设ThirdPartyLibraryType没有默认构造函数,我无法帮助它,因为它是第三方库类型。然后,此代码将无法编译,因为默认构造函数MyWrapper()必须调用ThirdPartyLibraryType的默认构造函数。现在我只希望默认构造函数不执行任何操作,因为我使用默认构造函数的用例如下:

std::array<MyWrapper,10> myArray;
for (int i=0;i<10;++i) {
    myArray[i] = generateMyWrapper(...);
}

有没有办法强制生成默认构造函数? (没有开销,我不想使用ThirdPartyLibraryType*有数据成员的明显解决方案)

修改 到目前为止,我使用的方法类似于Yakk提出的方法,它不依赖于默认构造函数,但我认为成员函数调用的情况很难看:

template<class T, size_t N, class C, class CF>
std::array<T,N> gen_array(C const& obj, CF&& f) {
    ...
    use obj.f
    ...
}

class MyClass {

    MyWrapper generateMyWrapper(int i) const { ... }

    auto genMyWrapperTypeArray() const {
        return 
            gen_array<
                 MyWrapper,10,MyClass,
                 MyWrapper(MyClass::*)(int) const
            > (
                *this, &MyClass::generateMyWrapper
            );
    }
}

我还没有对它进行测试,我的观点是,如果语法不完全相同,它仍然比我在默认构造函数可用时使用的简单for循环复杂得多。

2 个答案:

答案 0 :(得分:1)

std::experimental::optional或提升等价物有适度的开销,但可以处理eith&#34;这可能是或不构建&#34;。

不安全的等效物是std::aligned_storage_t你在哪里施工。问题是破坏,你需要知道它是否构建。

更好的选择可能是选择整个数组,而根本没有零参数ctor。打包构建每个参数所需的内容并创建一个构造函数,而不是循环。

template<class T, size_t...Is, class F>
std::array<T,sizeof...(Is)> gen_array(
  std::index_sequence<Is...>, F&&f
){
  return {{f(Is)...}};
)


template<class T, size_t N, class F>
std::array<T,N> gen_array(
  F&&f
){
  return gen_array(std::make_index_sequence<N>{}, f);
)

上面调用传递的lambda和每个元素的索引来构造元素。

答案 1 :(得分:1)

如果ThirdPartyLibraryType没有默认构造函数,则可能是由于有效的设计决策 / reason。

然后你有两种方法:

  • 要么为非默认构造函数找到一些合适的参数,要在包装器中使用它们;

  • 或者您推迟构建ThirdPartyLibraryType,直到您知道要使用哪个构造函数以及使用哪些参数。

第一种方法如下:

class MyWrapper {
    public:
        MyWrapper() : impl(/*parameters that you've selected*/) {};
    private:
       ThirdPartyLibraryType impl;
};

Perhap它适合您的需求,因为您已经知道要使用哪些构造函数参数,或者因为您可以负担得起构建廉价对象并在以后覆盖它。但这并不总是一个好主意......

第二种方法是使用您想要避免的指针。这种方法有许多优点:

  • 您可以在示例中构建巨大的默认初始化数组,并使用生成的对象覆盖不成功的默认包装器。
  • 您尊重您所依赖的库的设计,只构建有意义的对象。
  • 您可以减少对第三方库的依赖:需要您的包装器的编译单元不需要知道第三方类型,也不需要包含第三方库的标头(前向声明就足够了)。

事实上,明显的指针方法会使你的包装器实现SO answer