C++ 模板化默认构造函数

C++ 模板化默认构造函数,c++,templates,sfinae,C++,Templates,Sfinae,我希望在编译时通过模板参数切换默认构造函数的定义。我可以让它为转换构造函数编译OK,但尝试将该方法用于默认构造函数是否为默认构造函数——如果在特定模板参数的情况下,生成的类可能是POD,则很有用,但在另一种情况下,它不能——但这样做时会出现编译器错误。除了专门化模板和复制所有相同的代码之外,还有什么方法可以做到这一点吗?以下是我尝试的简化版本: #include<type_traits> // for enable_if template <bool MyParamete

我希望在编译时通过模板参数切换默认构造函数的定义。我可以让它为转换构造函数编译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;

};
#包括//for enable_如果
模板
课堂演示
{
公众:
//普通复制、移动构造函数/赋值和普通析构函数
constexpr演示(演示const&)=默认值;
constexpr演示(演示&)=默认值;
演示和运算符=(演示常量&)=默认值;
演示和运算符=(演示和运算符)=默认值;
~display()=默认值;
//这一条给出了“错误:模板不能被破坏”
模板::type=true>
演示()=默认值;
//嗯
模板::type=false>
演示():myValue(0){}
//嗯
模板::type=true>
显式constexpr演示(无符号字符转换)
:myValue(toConvert)
{
}
//嗯
模板::type=false>
显式constexpr演示(无符号字符转换)
:myValue(toConvert>100?0:toConvert)
{
}
//许多不依赖于参数的函数都在这里
受保护的:
私人:
无符号字符myValue;
};

GCC投诉您的模板:

error: a template cannot be defaulted
Clang抱怨说:

error: only special member functions may be defaulted.
这似乎很公平。成员函数模板不是成员函数, 更不用说特别的了

p
为真时,您希望
演示
为POD,否则 不一定如此

一个可能的解决方案是完全委托POD ness的参数化 到基本模板的专门化
base
,并具有
演示

继承
基础

。下面是一个例子:

#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;
}
#包括
模板
结构基//是POD
{
base()=默认值;
显式constexpr基(无符号字符ch)
:_val(ch){}
无符号字符;
};
模板
结构基//不是POD
{
base()=默认值;
显式constexpr基(无符号字符ch)
:_val(ch>100?0:ch){}
无符号字符_val=0;
};
模板
课堂示范:私人基地
{   
公众:
演示()=默认值;
//普通复制、移动构造函数/赋值和普通析构函数
constexpr演示(演示const&)=默认值;
constexpr演示(演示&)=默认值;
演示和运算符=(演示常量&)=默认值;
演示和运算符=(演示和运算符)=默认值;
~display()=默认值;
显式constexpr演示(无符号字符转换)
:基本(转换)
{
}
char myValue()常量{
返回基数::\u val;
}
};
#包括
使用名称空间std;
int main()
{

即使编译了它,
演示
在技术上仍然不是POD。“普通类是一个具有默认构造函数、没有非普通默认构造函数且可复制的类。”
演示
有两个默认构造函数,其中一个是非平凡的,即使它永远不可能是重载解析的可行函数。CRTP实现重复函数,并使这些构造函数具有两个专门化?您不能使用模板默认构造函数,因为您不能显式指定其模板参数。您可以只创建带有参数的模板构造函数,这些参数将允许编译器推断其模板参数。您可以尝试使用模板静态函数实现所需的功能,该函数返回
演示
类的构造对象。谢谢大家,这消除了我的困惑。@Yakk:CRTP看起来是实现基于模板参数的类可以是POD或非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