Выбор функции-члена с использованием различных условий enable_if

Я пытаюсь определить, какая версия функции-члена вызывается на основе параметра шаблона класса. Я попробовал это:

#include <iostream>
#include <type_traits>

template<typename T>
struct Point
{
void MyFunction(typename std::enable_if<std::is_same<T, int>::value, T >::type* = 0)
{
std::cout << "T is int." << std::endl;
}

void MyFunction(typename std::enable_if<!std::is_same<T, int>::value, float >::type* = 0)
{
std::cout << "T is not int." << std::endl;
}
};

int main()
{
Point<int> intPoint;
intPoint.MyFunction();

Point<float> floatPoint;
floatPoint.MyFunction();
}

я подумал: «используйте первую MyFunction, если T — int, и используйте вторую MyFunction, если T — не int, но я получаю ошибки компилятора, говорящие« error: нет типа с именем ‘type’ в ‘struct std :: enable_if’ » Кто-нибудь может указать, что я здесь делаю не так?

11

Решение

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

В вашем примере не происходит подстановка при создании экземпляров функций-членов, потому что аргумент шаблона T уже известно в то время. Самый простой способ добиться того, что вы пытаетесь сделать, — создать фиктивный аргумент шаблона, который по умолчанию равен T и использовать это для выполнения SFINAE.

template<typename T>
struct Point
{
template<typename U = T>
typename std::enable_if<std::is_same<U, int>::value>::type
MyFunction()
{
std::cout << "T is int." << std::endl;
}

template<typename U = T>
typename std::enable_if<std::is_same<U, float>::value>::type
MyFunction()
{
std::cout << "T is not int." << std::endl;
}
};

Редактировать:

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

template<typename T>
struct Point
{
template<typename... Dummy, typename U = T>
typename std::enable_if<std::is_same<U, int>::value>::type
MyFunction()
{
static_assert(sizeof...(Dummy)==0, "Do not specify template arguments!");
std::cout << "T is int." << std::endl;
}

template<typename... Dummy, typename U = T>
typename std::enable_if<std::is_same<U, float>::value>::type
MyFunction()
{
static_assert(sizeof...(Dummy)==0, "Do not specify template arguments!");
std::cout << "T is not int." << std::endl;
}
};
11

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

Простое решение заключается в использовании делегирования работнику частный функции:

template<typename T>
struct Point
{

void MyFunction()
{
worker(static_cast<T*>(0)); //pass null argument of type T*
}

private:

void worker(int*)
{
std::cout << "T is int." << std::endl;
}

template<typename U>
void worker(U*)
{
std::cout << "T is not int." << std::endl;
}
};

когда T является int, первый worker функция будет вызвана, потому что static_cast<T*>(0) оказывается типа int*, Во всех остальных случаях будет вызываться шаблонная версия работника.

2

enable_if работает только для счислимый аргументы шаблона функции или для специализированных аргументов шаблона класса. То, что вы делаете, не работает, потому что, очевидно, с фиксированным T = intВторое объявление просто ошибочно.

Вот как это можно сделать:

template <typename T>
void MyFreeFunction(Point<T> const & p,
typename std::enable_if<std::is_same<T, int>::value>::type * = NULL)
{
std::cout << "T is int" << std::endl;
}

// etc.

int main()
{
Point<int> ip;
MyFreeFunction(ip);
}

Альтернативой было бы специализироваться Point для разных типов Tили поместить вышеупомянутую свободную функцию в оболочку шаблона вложенного элемента (что, вероятно, является более «правильным» решением).

1

Основываясь на предложении Преториана (но без изменения типа возвращаемого значения функции), это похоже на работу:

#include <iostream>
#include <type_traits>

template<typename T>
struct Point
{
template<typename U = T>
void MyFunction(typename std::enable_if<std::is_same<U, int>::value, U >::type* = 0)
{
std::cout << "T is int." << std::endl;
}

template<typename U = T>
void MyFunction(typename std::enable_if<!std::is_same<U, int>::value, float >::type* = 0)
{
std::cout << "T is not int." << std::endl;
}
};

int main()
{
Point<int> intPoint;
intPoint.MyFunction();

Point<float> floatPoint;
floatPoint.MyFunction();
}
0

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

Чтобы ответить на вопрос: здесь worker () вызывается точно в зависимости от параметра шаблона вызова метода (), но все же вы управляете типами.

    template<typename T>
struct Point
{
static_assert (
std::is_same<T, int>()  ||
std::is_same<T, float>()
);

template<typename U>
void method(U x_, U y_)
{
if constexpr (std::is_same<T, U>()) {
worker(x_, y_);
return;
}
// else
worker(
static_cast<T>(x_),
static_cast<T>(y_)
);
return ;
}private:

mutable T x{}, y{};

void worker(T x_, T y_)
{
// nothing but T x, T y
}

};

Выше работник (), конечно, будет работать, даже если он объявлен как статический. По какой-то уважительной причине. Несколько других расширений к вышеупомянутому возможны (и просты), но давайте придерживаться ответа.

0
По вопросам рекламы [email protected]