Портирование с MSVC2015 Update 2 на GCC 5.3 — ошибки SFINAE

В настоящее время я портирую свою библиотеку, но мой темный шаблон не будет скомпилирован с GCC 5.3

Этот фрагмент работает должным образом при компиляции с MSVC2015 Update 2

template<typename vreal =
std::enable_if<std::is_vreal<vreal>::value,
floatType>::type>
inline vreal foo(vreal bar)
{
return bar;
}

template<typename vreal =
std::enable_if<std::is_vreal<vreal>::value,
floatType>::type>
struct bar { vreal i; };

GCC жалуется на «vreal не был определен в текущей области (WTF?)»

Что я пробовал до сих пор:

Перепишите верхний фрагмент шаблона в

template<typename vreal,
typename enable = typename std::enable_if<std::is_vreal<vreal>::value != 0>::type>

Но это тоже не работает. Это намного позже в коде, и я предполагаю, что это связано с введением дополнительного параметра шаблона.

Кроме того, я не понимаю, почему мне пришлось вводить сравнение с 0. Без этого gcc жаловался на отсутствие ‘type’ в enabled_if.

Итак, главный вопрос: как получить ту же логику SFINAE (скомпилировать ТОЛЬКО, если аргумент vreal) БЕЗ дополнительных аргументов.

Я мог бы переписать это, чтобы вернуть тип SFINAE — но это было бы большой работой, которую я хотел бы избежать (различие между функциями, классами, структурами, typedefs / usings …), даже если оно заключено в макрос.

 template<typename vreal>
typename std::enable_if<is_vreal<vreal>, vreal>::type inline vreal .....

0

Решение

Это не допустимый C ++:

template<typename vreal =
std::enable_if<std::is_vreal<vreal>::value,
floatType>::type>
inline vreal foo(vreal bar)
{
return bar;
}

по многим причинам. Он использует символ в std это не в std (is_vreal), что означает, что ваша программа плохо сформирована. Использует токен floatType это не определено (вы опубликовали [MCVE] правильно?). Оно использует vreal прежде чем это входит в сферу, в определении vreal,

Я понятия не имею, что это должно означать, кроме вашей кажущейся веры в то, что она делает СФИНА магию: она утверждает, что если vreal проходит is_vreal тест, это должен быть тип floatType по умолчанию. Но чтобы достичь этой точки, вы должны были иметь тип vreal уже, поэтому тип по умолчанию, кажется, не имеет значения.

Также, ::type не является типом в зависимом контексте :, так std::enable_if<std::is_vreal<vreal>::value, floatType>::type должен жаловаться, что вы используете не тип по имени ::type в контексте, где ожидается тип. Вам нужно сделать typenam estd::enable_if<std::is_vreal<vreal>::value, floatType>::type,

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

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

Исключение составляют функции, поскольку возможны перегрузки, вы можете ввести помощника SFINAE.

Откажитесь от макроса полностью. Шаблоны классов и функций в любом случае работают значительно по-разному.

Для классов / структур:

template<class vreal>
struct bar { vreal i; };

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

Для функций нам нужен тест SFINAE, чтобы мы могли перегрузить:

template<class T, class R=T>
using vreal_test = typename
std::enable_if<std::is_vreal<T>::value, R>::type

template<class vreal>
inline vreal_test<vreal> foo(vreal bar)
{
return bar;
}

если функция возвращает другой тип, выполните

template<class vreal>
inline vreal_test<vreal,void> foo2(vreal bar)
{
return;
}

Вы можете сделать это, когда вы подметаете, чтобы удалить макрос.

1

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

Для вашей главной функции вы можете иметь это:

template<typename vreal>
inline typename std::enable_if<std::is_vreal<vreal>::value, floatType>::type foo(vreal bar)
{
return bar;
}

Ваша структура также должна быть переопределена. Приведенное ниже решение не может обойтись без использования вторичного параметра Enable here с частичной специализацией:

template<typename vreal, typename Enable = void>
struct bar;

template<typename vreal>
struct bar<vreal, typename std::enable_if<std::is_vreal<vreal>::value, void>::type>
{ vreal i; };

(Предполагая, что floatType и std :: is_vreal определены где-то соответствующим образом)

0

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

Для структуры я бы использовал enable_if и специализировать базовый класс.

Это будет выглядеть так:

template<typename vreal, typename std::enable_if<std::is_vreal<vreal>::value, int>::type = 0>
vreal foo(vreal bar) {
return bar;
}

template<typename vreal, typename = void>
struct barBase; // optionally add a static_assert for better messages

template<typename vreal>
struct barBase<vreal, typename std::enable_if<std::is_vreal<vreal>::value>::type> {
vreal i;
};

template<typename vreal>
using bar = barBase<vreal>;

Я не думаю std::is_vreal существует. Если это так, конечно, не в GCC. Не вводите вещи в пространство имен std, компиляторы могут отказаться от него.

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