В настоящее время я портирую свою библиотеку, но мой темный шаблон не будет скомпилирован с GCC 5.3
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 .....
Это не допустимый 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;
}
Вы можете сделать это, когда вы подметаете, чтобы удалить макрос.
Для вашей главной функции вы можете иметь это:
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 определены где-то соответствующим образом)
Я бы отделил 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, компиляторы могут отказаться от него.