Смешивание шаблонной функции с перегрузкой и наследованием - PullRequest
4 голосов
/ 07 декабря 2010

Распечатывается следующий код:

generic
overload

Но я хотел, чтобы перегрузка или специализация были вызваны в обоих случаях, а не в общем. Я не пытаюсь смешать перегрузку со специализацией шаблонов, они здесь вместе, потому что никто не работал так, как я ожидал Есть ли какая-то магия шаблонов для этого?

#include <iostream>

class Interface {};
class Impl: public Interface {};

class Bar
{
public:
    template<typename T> void foo(T& t) {
        std::cout << "generic\n";
    }
    void foo(Interface& t) {
        std::cout << "overload\n";
    }
};
template<> void Bar::foo<Interface>(Interface& t) {
    std::cout << "specialization\n";
}

int main() {
    Bar bar;
    Impl impl;
    Interface& interface = impl;
    bar.foo(impl);
    bar.foo(interface);
    return 0;
}

Ответы [ 3 ]

5 голосов
/ 07 декабря 2010

Два способа использовать type_traits для проверки, является ли аргумент полученным из интерфейса.

#include <boost/type_traits.hpp>

class Interface {};
class Impl: public Interface {};

class Bar
{
    template <class T> void foo_impl(T& value, boost::false_type)
    {
        std::cout << "generic\n";
    }
    void foo_impl(Interface& value, boost::true_type)
    {
        std::cout << "Interface\n";
    }
public:
    template<typename T> void foo(T& t) {
        foo_impl(t, boost::is_base_of<Interface, T>());
    }

};

Или отключить шаблон, если выполняется условие, оставив только не шаблон в качестве кандидата.

#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>

class Interface {};
class Impl: public Interface {};

class Bar
{
public:
    template<typename T>
    typename boost::disable_if<boost::is_base_of<Interface, T>, void>::type foo(T& t)
    {
        std::cout << "generic\n";
    }

    void foo(Interface&)
    {
        std::cout << "Interface\n";
    }
};
2 голосов
/ 07 декабря 2010

Чтобы использовать специализированную функцию, компилятору необходимо выполнить преобразование параметра из &Impl в &Interface. Когда он ищет совпадение сигнатуры функции, точные совпадения предпочтительнее тех, которые требуют преобразования. Так как универсальный foo<T> является точным соответствием, он выигрывает как от перегрузки, так и от специализированной функции.

0 голосов
/ 07 декабря 2010

Определение шаблона позволяет создать функцию:

void Bar::foo<Impl>(Impl& t)

, что лучше, чем те, которые вы определили, которые принимают параметр Interface&.

Вы должны сделатьфункция суперкласса лучше соответствует, возможно, так:

class Bar
{
    struct fallback { fallback(int) {} };
    template<typename T> void foo(T& t, fallback) {
        std::cout << "generic\n";
    }
    void foo(Interface& t, int) {
        std::cout << "overload\n";
    }
public:
    template<typename T> void foo(T& t) {
        foo(t, 0);
    }
};

Кажется, что на самом деле это не работает, см. http://ideone.com/IpBAv

Так что вам понадобится проверка типа внутри общеговерсия, ищет подклассы Interface.

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