Как правильно выбрать шаблон перегруженной функции во время компиляции? - PullRequest
2 голосов
/ 09 февраля 2011

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

У меня есть две структуры A и B, как показано ниже.У одного есть специальная функция, а у другого - нормальная.

struct A
{
    void special() { std::cout << "special called.\n"; }
};

struct B
{
    void normal() { std::cout << "normal called.\n"; }
};

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

template<class Func, Func f> struct Sfinae {};

template <typename U>
static void run(U& u, Sfinae<void (U::*)(), &U::special>* = 0)
{
    u.special();
}

template <typename U>
static void run(U& u, ...)
{
    u.normal();
}

Я проверил это с помощью следующих результатов, с различными результатами:

int main()
{
    A a;
    run<A>(a, 0); // works
    run<A>(a); // ERROR: ambiguous overloaded function
    run(a, 0); // ERROR: A has no member normal
    run(a); // ERROR: ambiguous overloaded function

    B b;
    run<B>(b, 0); // works
    run<B>(b); // works
    run(b, 0); // works
    run(b); // works

    return 0;
}

Я бы хотел использовать его как run(a) без каких-либо дополнительных аргументов или <>.Что-то не так с моим кодом, когда он не работает?

Кроме того, мне интересно понять, что здесь происходит и почему это приводит к таким вещам, поэтому мне нужно дать <A> дляA но не для B?Я не знаю, что говорится в стандарте, и если это отличается в разных компиляторах, но, по крайней мере, gcc4.4.4 в Linux и gcc 4.0.1 в Mac работают так, как я описал.

Может кто-нибудь, пожалуйста, пролить немногосвет на это?Спасибо!

Ответы [ 2 ]

1 голос
/ 09 февраля 2011

Это здесь будет работать.Это своего рода предполагает, что две функции, обычная и специальная, являются взаимоисключающими (т.е. класс, у которого одна из них не имеет другой).Я уверен, что вы можете адаптировать его к своей цели.Это использует boost::enable_if, конечно.

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

struct A
{
    void special() { std::cout << "special called.\n"; }
};

struct B
{
    void normal() { std::cout << "normal called.\n"; }
};

template<int> struct Sfinae { enum { value = true }; };

template <typename U>
static typename boost::enable_if<Sfinae<sizeof(&U::special)>,void>::type run(U& u)
{
    u.special();
}

template <typename U>
static typename boost::enable_if<Sfinae<sizeof(&U::normal)>,void>::type run(U& u)
{
    u.normal();
}


int main()
{
    A a;
    run(a); // works

    B b;
    run(b); // works

    return 0;
}

Это работает на gcc 4.6.0 в Linux.

1 голос
/ 09 февраля 2011

Для этой конкретной ситуации вы можете сделать это, что очень просто:

template <typename U>
static void run(U & u)
{
    u.special();
}

template <>
static void run<B>(B &u)
{
    u.normal();
}

Или вы можете просто удалить шаблон и написать две перегруженные функции. Я согласен, это не решает в более общем смысле.

Возможно, эта тема поможет вам найти общее решение:

Можно ли написать шаблон для проверки существования функции?

См. Ответ Йоханнеса. : -)

...