Изменить приоритет конструктора - PullRequest
4 голосов
/ 19 апреля 2011

Можно ли определить конструктор для всех производных типов и конструктор шаблона? Я написал этот тест для иллюстрации моей проблемы:

#include <iostream>


class Variant;
class CustomVariant;


class Variant
{
public:
    Variant(void)
        {}


    Variant(const Variant&)
        {
            std::cout << "ctor" << std::endl;
        }


    Variant(const CustomVariant&)
        {
            std::cout << "custom" << std::endl;
        }


    template<typename T>
    Variant(const T&)
        {
            std::cout << "template" << std::endl;
        }
};


class CustomVariant : public Variant
{
};


class DerivedVariantA : public CustomVariant
{
};


class DerivedVariantB : public CustomVariant
{
};


int main(void)
{

    DerivedVariantB dvb;

    Variant v(dvb);
    // expcected output: "custom" instead of "template"

}

Ответы [ 2 ]

6 голосов
/ 19 апреля 2011
template <typename T> Variant(const T&)  // (a)
Variant(const CustomVariant&)            // (b)

Не требуется преобразования для вызова (a) ;тип аргумента, DerivedVariantB, является точным совпадением, где T = DerivedVariantB.

Требуется преобразование из производной в базовую область для вызова (b) .Следовательно, (a) лучше, чем (b) .

Если вы вызываете конструктор с аргументом типа CustomVariant, оба конструктора являются точнымисовпадает, поэтому (b) выбрано потому, что если все остальное равно, шаблон не является предпочтительным по сравнению с шаблоном.

Вы можете запретить использование шаблона, где T получено из Variant с помощью std::enable_if:

template<typename T>
Variant(const T&, 
        typename std::enable_if<
                     !std::is_base_of<Variant, T>::value, void*
                 >::type = 0)
{
    std::cout << "template" << std::endl;
}

Это делает шаблон не подлежащим созданию, когда T получено из Variant, поэтому он не будет доступен во время разрешения перегрузки.enable_if и is_base_of являются новыми для C ++ в C ++ 0x, и ваш компилятор и стандартная библиотека могут их поддерживать.Если нет, вы также можете найти их в C ++ TR1 или Boost.TypeTraits .

0 голосов
/ 19 апреля 2011

Нет, среди списка конструкторов, доступных в классе, нет конструктора, который принимает экземпляр типа DerivedVariantB в качестве аргумента. Следовательно, генерируемый шаблон вызывается.

class DerivedVariantB ; // Forward Declaration

class Variant
{
    public:
    // ...

     Variant( const DerivedVariantB &obj )
     {
         std::cout << "\n DerivedVariantB \n";
     }
};

Теперь можно вызвать конструктор, который получает ссылку типа DerivedVariantB вместо сгенерированного шаблона.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...