Шаблон Конструктор по подразбиране

Бих искал дефиницията на конструктора по подразбиране да бъде превключвана по време на компилиране чрез параметър на шаблон. Мога да накарам това да компилира ОК за конструктор на преобразуване, но се опитвам да използвам този метод за конструктор по подразбиране, за да бъде по подразбиране или не - полезно, ако в случай на конкретен параметър на шаблона, полученият клас може да бъде 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;

};

person Signifying Nothing    schedule 06.04.2014    source източник
comment
Дори ако това бъде компилирано, Demonstration<true> технически все още няма да бъде POD. Тривиален клас е клас, който има конструктор по подразбиране, няма нетривиални конструктори по подразбиране и е тривиално копируем. Demonstration<true> има два конструктора по подразбиране и единият е нетривиален, въпреки че никога не може да бъде жизнеспособна функция за разрешаване на претоварване.   -  person aschepler    schedule 06.04.2014
comment
CRTP изпълнява дублиращите се функции и дали ctors са в две специализации?   -  person Yakk - Adam Nevraumont    schedule 06.04.2014
comment
Не можете да използвате конструктора по подразбиране на шаблона, защото не можете изрично да посочите неговите аргументи на шаблона. Можете да създавате само конструктори на шаблони с параметри, които биха позволили на компилатора да изведе своите аргументи на шаблона. Можете да опитате да постигнете това, което искате, със статична функция на шаблона, която връща конструиран обект от клас Demonstration.   -  person Constructor    schedule 06.04.2014
comment
Благодаря на всички ви, това изяснява объркването ми. @Yakk: CRTP наистина изглежда начинът да се постигне класът да бъде POD или не-POD въз основа на параметър на шаблон без много дублиране; ако изпратите това като отговор, ще го приема.   -  person Signifying Nothing    schedule 07.04.2014
comment
@signifyingnothing naw, само си отговорете: не мога да си направя труда да напиша добър в момента. А лош отговор не си струва да се пише.   -  person Yakk - Adam Nevraumont    schedule 07.04.2014


Отговори (1)


GCC се оплаква от вашия шаблон:

error: a template cannot be defaulted

и Кланг се оплаква:

error: only special member functions may be defaulted.

Това изглежда достатъчно справедливо. Шаблон за членска функция не е членска функция, да не говорим за специална.

Бихте искали Demonstration<bool P> да бъде POD, когато P е вярно, а в противен случай не е задължително да е така.

Възможно решение е да се делегира параметризирането на POD-ness изцяло на специализации на базов шаблон base<bool P> и Demonstration<P> да наследява base<P>. Ето една илюстрация:

#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<P> е POD само в случай, че base<P> е 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

person Mike Kinghan    schedule 11.04.2014