通过删除析构函数的非instatiable类?

时间:2016-08-24 22:02:14

标签: c++11 instantiation deleted-functions

我有一个class用于纯粹的语法目的,以某种方式调用函数。这是一个简化的例子:

#include<iostream>

template<class T1>
struct make{
    template<class T2>
    static T1 from(T2 const& t2){
        return T1{}; //or something more complicated
    }
};

int main(){
    double d = make<double>::from(2);
    std::cout << d << '\n';
}

现在,假设我想警告用户不应该实例化此类。 该课程可能有用,但是  如果有可能禁止,我有好奇心吗?

首先我尝试删除默认构造函数

template<class T1>
struct make{
    make() = delete;
    template<class T2>
    static T1 from(T2 const& t2){
        return T1{}; //or something more complicated
    }
};

但是这仍然是可能的:

make<double> m{}; // valid

最后,我尝试删除析构函数,这似乎有效

template<class T1>
struct make{
    ~make() = delete;
    template<class T2>
    static T1 from(T2 const& t2){
        return T1{}; //or something more complicated
    }
};

但似乎那个班级仍然可以由new分配。

我应该删除析构函数和删除构造函数,(复制和移动构造函数怎么样?)

这是禁止实例化的最佳方法吗? 代码在这里:http://coliru.stacked-crooked.com/a/0299c377c129fffb

#include<iostream>

template<class T1>
struct make{
    make() = delete;
    ~make() = delete;
    template<class T2>
    static T1 from(T2 const& t2){
        return T1{}; //or something more complicated
    }
};

int main(){
    double d = make<double>::from(2);
    std::cout << d << '\n';
    make<double> m{}; // compile error (no destructor)
    auto p = new make<double>{}; // compile error (no constructor)
}

1 个答案:

答案 0 :(得分:3)

  

但是这仍然是可能的:

make<double> m{}; // valid

......我不知道那会起作用。但是现在我这样做了,我也知道为什么它有效。因此,如何阻止它。

它的工作原理是make<T>,因为你声明它是一个聚合。即使它有一个删除的默认构造函数,C ++仍然认为它是一个聚合。如果您在聚合上使用braced-init-lists,则会得到aggregate initialization

阻止它的方法很简单:让它不再是聚合:

template<class T1>
struct make{
    template<class T2>
    static T1 from(T2 const& t2){
        return T1{}; //or something more complicated
    }

    make() = delete;

private:
    char c; //Not an aggregate
};

该私人成员强制make<T>不再是聚合。因此,它不能与聚合初始化一起使用,因此{}将尝试调用默认构造函数。由于它被删除,自然会失败。

可以使用平凡的可复制体操来创建make<T>的实例。你可以通过给它一个virtual析构函数来关闭它们:

template<class T1>
struct make{
    template<class T2>
    static T1 from(T2 const& t2){
        return T1{}; //or something more complicated
    }

    make() = delete;

private:
    char c; //Not an aggregate
    virtual ~make() = default;
};

这应该足以阻止合法C ++代码创建该类型的对象。