Запретить неявное преобразование в методе на основе шаблона

Предположим, у нас есть что-то вроде этого:

template <class B>
class A
{
void Foo(B& b)
{
b.Bar(0.5);
}
};

class B
{
void Bar(float) {}
void Bar(double) {}
void Bar(int) {}
};

В этом коде введите B должен предоставить метод Bar() который принимает аргумент некоторого целочисленного типа. Проблема здесь во всех 3 версиях B::Bar() разрешены. Есть ли способ разрешить только одну версию этих методов, например, только компилировать, если B обеспечивает Bar(float)?

0

Решение

Вы можете использовать эту (ужасную) технику, которая приведет к сбою компиляции, если A создается с типом B это не имеет общественности void Foo(float) член, пытаясь извлечь из него определенный тип указателя на член.

template <class B>
class A
{
public:
void Foo(B& b)
{
static_cast<void (B::*)(float)>(&B::Bar);

b.Bar(0.5);
}
};

(Демонстрация полученной ошибки компиляции.)

Если вы действительно хотите вызвать этот метод, тогда вам нужно использовать b.Bar(0.5f);, 0.5 это double буквальный, а не float буквально, так что вы должны убедиться, что у него есть правильный член, но затем, если у него есть void Bar(double) Вы бы назвали это так или иначе. Изменение константы на 0.5f бы исправить это.

Обратите внимание, что поскольку взятие указателя не имеет побочных эффектов и результат не используется, любой приличный компилятор оптимизирует это как неиспользуемое.


Вы также можете пойти по традиционному маршруту SFINAE примерно так:

template <typename T, typename TMethod>
class has_bar_method
{
private:
struct yes { char _; };
struct no { char _[2]; };
template <typename U, TMethod = &U::Bar>
static yes impl(U*);
static no impl(...);

public:
enum { value = sizeof(impl(static_cast<T*>(nullptr))) == sizeof(yes) };
};

Используется так:

void Foo(T& b)
{
static_assert(has_bar_method<T, void (T::*)(float)>::value,
"T has method void Bar(float)");

b.Bar(0.5f);
}

Теперь, если шаблон не может быть создан, мы получаем хорошее сообщение, объясняющее почему:

prog.cpp: 25: 8: ошибка: статическое утверждение не выполнено: T имеет метод void Bar (float)

(демонстрация)

1

Другие решения


По вопросам рекламы ammmcru@yandex.ru