【问题标题】:Templated Defaulted default constructor模板化的默认默认构造函数
【发布时间】:2014-05-18 08:11:50
【问题描述】:

我希望在编译时通过模板参数切换默认构造函数的定义。我可以让它为转换构造函数编译 OK,但尝试使用该方法使默认构造函数被默认或不被默认 - 如果在特定模板参数的情况下,结果类可能是 POD,则很有用,但在另一种情况下,它不能 - 但这样做时我得到一个编译器错误。没有专门的模板和复制所有相同的代码,有没有办法做到这一点?这是我尝试的简化版本:

#include<type_traits>   // for enable_if

template <bool MyParameter>
class Demonstration
{
    public:

        //trivial copy, move constructors/assignment, and trivial destructor
        constexpr Demonstration(Demonstration const &) = default;
        constexpr Demonstration(Demonstration &&) = default;
        Demonstration & operator= (Demonstration const &) = default;
        Demonstration & operator= (Demonstration &&) = default;
        ~Demonstration() = default;

        // this one gives "error: a template cannot be defauled"
        template <bool Dummy=MyParameter, typename std::enable_if< Dummy , bool >::type=true >
        Demonstration() = default;

        // ok
        template <bool Dummy=MyParameter, typename std::enable_if< !Dummy , bool >::type=false >
        Demonstration() : myValue(0) {}

        // ok
        template <bool Dummy=MyParameter, typename std::enable_if< Dummy , bool >::type=true >
        explicit constexpr Demonstration(unsigned char toConvert)
        : myValue ( toConvert )
        {
        }
        // ok
        template <bool Dummy=MyParameter, typename std::enable_if< !Dummy , bool >::type=false >
        explicit constexpr Demonstration(unsigned char toConvert)
        : myValue ( toConvert > 100 ? 0 : toConvert )
        {
        }

    // a lot of functions that do not depend on parameter go here

    protected:
    private:
        unsigned char myValue;

};

【问题讨论】:

  • 即使编译了这个,Demonstration&lt;true&gt; 在技术上仍然不是 POD。 “普通类是具有默认构造函数的类,没有非普通默认构造函数,并且可以轻松复制。” Demonstration&lt;true&gt; 有两个默认构造函数,一个很重要,尽管它永远不可能成为重载决议的可行函数。
  • CRTP 实现了重复的功能,并且 ctor 有两个专业?
  • 您不能使用模板默认构造函数,因为您不能显式指定其模板参数。您只能使用允许编译器推断其模板参数的参数创建模板构造函数。您可以尝试使用模板静态函数来实现您想要的,该函数返回 Demonstration 类的构造对象。
  • 谢谢大家,这消除了我的困惑。 @Yakk:CRTP 确实看起来是一种基于模板参数将类设为 POD 或非 POD 的方法,而无需大量重复;如果您将其作为答案提交,我会接受。
  • @signifyingnothing 不,只是自我回答:我现在懒得写一篇好文章。一个糟糕的答案不值得写。

标签: c++ templates sfinae


【解决方案1】:

GCC 抱怨您的模板:

error: a template cannot be defaulted

Clang 抱怨:

error: only special member functions may be defaulted.

这似乎很公平。成员函数模板不是成员函数, 更不用说特别的了。

P 为真时,您希望Demonstration&lt;bool P&gt; 成为POD,否则 不一定。

一种可能的解决方案是完全委托 POD 的参数化 基础模板的专业化base&lt;bool P&gt; 并具有 Demonstration&lt;P&gt; 继承 base&lt;P&gt;。这是一个插图:

#include<type_traits>

template<bool Param = true>
struct base // is POD 
{
    base() = default;
    explicit constexpr base(unsigned char ch)
    : _val(ch){}
    unsigned char _val;
};

template<>
struct base<false> // is not POD
{
    base() = default;
    explicit constexpr base(unsigned char ch)
    : _val(ch > 100 ? 0 : ch){}
    unsigned char _val = 0;
};


template <bool MyParameter>
class Demonstration : private base<MyParameter>
{   
public:

    Demonstration() = default;
    //trivial copy, move constructors/assignment, and trivial destructor
    constexpr Demonstration(Demonstration const &) = default;
    constexpr Demonstration(Demonstration &&) = default;
    Demonstration & operator= (Demonstration const &) = default;
    Demonstration & operator= (Demonstration &&) = default;
    ~Demonstration() = default;

    explicit constexpr Demonstration(unsigned char toConvert)
    : base<MyParameter>(toConvert)
    {
    }

    char myValue() const {
        return base<MyParameter>::_val;
    }
};


#include <iostream>

using namespace std;

int main()
{
    cout << "is_pod<base<true>>::value = " 
        << is_pod<Demonstration<true>>::value << endl;
    cout << "is_pod<base<false>>::value = " 
        << is_pod<Demonstration<false>>::value << endl;
    cout << "is_pod<Demonstration<true>>::value = " 
        << is_pod<Demonstration<true>>::value << endl;
    cout << "is_pod<Demonstration<false>>::value = " 
        << is_pod<Demonstration<false>>::value << endl;
    Demonstration<true> d_true(1);
    Demonstration<false> d_false(101);
    std::cout << "(int)Demonstration<true>(1).myValue() = " 
        << (int)d_true.myValue() << endl;
    std::cout << "(int)Demonstration<false>(101).myValue() = " 
        << (int)d_false.myValue() << endl;
    return 0;
}

现在Demonstration&lt;P&gt; 是 POD,以防万一 base&lt;P&gt; 是 POD。该程序 输出:

is_pod<base<true>>::value = 1
is_pod<base<false>>::value = 0
is_pod<Demonstration<true>>::value = 1
is_pod<Demonstration<false>>::value = 0
(int)Demonstration<true>(1).myValue() = 1
(int)Demonstration<false>(101).myValue() = 0

使用 GCC 4.8.2 和 clang 3.3 构建

【讨论】:

    猜你喜欢
    • 2016-06-24
    • 2011-03-27
    • 1970-01-01
    • 1970-01-01
    • 2016-07-23
    • 2016-03-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-13
    相关资源
    最近更新 更多