Бесконечная рекурсия шаблона, потому что нет оптимизации bool-выражения только с помощью gcc - PullRequest
1 голос
/ 13 марта 2019

Я работаю над лексическим заклинателем. Смотрите ниже упрощенную, проблемную часть кода ниже. Код компилируется с помощью clang и msvc, но не компилируется с gcc. Кажется, что в первом аргументе std::enable_if gcc lexicalCast пытается вычислить весь операнд выражения bool перед его оценкой, в то время как clang и msvc проводят оптимизацию и игнорируют оценку LexicalCastable<>:: value, если выражения std::is_same не сработали. Мои вопросы будут:

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

Код:

#include <type_traits>
#include <string>

template<typename From, typename To>
class LexicalCastable;

template<typename To, typename From> typename
    std::enable_if<
           !std::is_same<std::string, To>::value
        && !std::is_same<std::string, From>::value
        && LexicalCastable<From, std::string>::value
        && LexicalCastable<std::string, To>::value,
To>::type lexicalCast(const From &from) {
    return lexicalCast<To>(lexicalCast<std::string>(from));
}

template<typename From, typename To>
class LexicalCastable
{
    template<typename TT>
    static auto test(int)
        -> decltype(lexicalCast<TT>(std::declval<From>()), std::true_type{});

    template<typename>
    static auto test(...)->std::false_type;

public:
    static const bool value = decltype(test<To>(0))::value;
};

static_assert(!LexicalCastable<std::string, std::string>::value, "");

Ошибки с gcc:

prog.cpp: In substitution of ‘template<class TT> static decltype ((lexicalCast<TT>(declval<From>()), std::true_type{})) LexicalCastable<From, To>::test(int) [with TT = std::__cxx11::basic_string<char>]’:
prog.cpp:35:45:   required from ‘const bool LexicalCastable<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >::value’
prog.cpp:19:3:   required by substitution of ‘template<class To, class From> typename std::enable_if<(((((! std::is_constructible<To, From>::value) && (! std::is_same<std::__cxx11::basic_string<char>, To>::value)) && (! std::is_same<std::__cxx11::basic_string<char>, From>::value)) && LexicalCastable<From, std::__cxx11::basic_string<char> >::value) && LexicalCastable<std::__cxx11::basic_string<char>, To>::value), To>::type lexicalCast(const From&) [with To = std::__cxx11::basic_string<char>; From = <missing>]’
prog.cpp:29:30:   required by substitution of ‘template<class TT> static decltype ((lexicalCast<TT>(declval<From>()), std::true_type{})) LexicalCastable<From, To>::test(int) [with TT = std::__cxx11::basic_string<char>]’
prog.cpp:35:45:   required from ‘const bool LexicalCastable<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >::value’
prog.cpp:19:3:   required by substitution of ‘template<class To, class From> typename std::enable_if<(((((! std::is_constructible<To, From>::value) && (! std::is_same<std::__cxx11::basic_string<char>, To>::value)) && (! std::is_same<std::__cxx11::basic_string<char>, From>::value)) && LexicalCastable<From, std::__cxx11::basic_string<char> >::value) && LexicalCastable<std::__cxx11::basic_string<char>, To>::value), To>::type lexicalCast(const From&) [with To = std::__cxx11::basic_string<char>; From = <missing>]’
prog.cpp:29:30:   [ skipping 889 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
prog.cpp:35:45:   required from ‘const bool LexicalCastable<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >::value’
prog.cpp:19:3:   required by substitution of ‘template<class To, class From> typename std::enable_if<(((((! std::is_constructible<To, From>::value) && (! std::is_same<std::__cxx11::basic_string<char>, To>::value)) && (! std::is_same<std::__cxx11::basic_string<char>, From>::value)) && LexicalCastable<From, std::__cxx11::basic_string<char> >::value) && LexicalCastable<std::__cxx11::basic_string<char>, To>::value), To>::type lexicalCast(const From&) [with To = std::__cxx11::basic_string<char>; From = <missing>]’
prog.cpp:29:30:   required by substitution of ‘template<class TT> static decltype ((lexicalCast<TT>(declval<From>()), std::true_type{})) LexicalCastable<From, To>::test(int) [with TT = std::__cxx11::basic_string<char>]’
prog.cpp:35:45:   required from ‘const bool LexicalCastable<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >::value’
prog.cpp:19:3:   required by substitution of ‘template<class To, class From> typename std::enable_if<(((((! std::is_constructible<To, From>::value) && (! std::is_same<std::__cxx11::basic_string<char>, To>::value)) && (! std::is_same<std::__cxx11::basic_string<char>, From>::value)) && LexicalCastable<From, std::__cxx11::basic_string<char> >::value) && LexicalCastable<std::__cxx11::basic_string<char>, To>::value), To>::type lexicalCast(const From&) [with To = std::__cxx11::basic_string<char>; From = <missing>]’
prog.cpp:40:43:   required from here
prog.cpp:29:49: fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)
   -> decltype(lexicalCast<TT>(std::declval<From>()), std::true_type{});
                               ~~~~~~~~~~~~~~~~~~^~

1 Ответ

3 голосов
/ 13 марта 2019

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

Вы можете использовать std::conjunction (C ++ 17), который гарантирует короткое замыкание

template <typename To, typename From>
typename std::enable_if<
    std::conjunction<
           std::negation<std::is_same<std::string, To>>,
           std::negation<std::is_same<std::string, From>>,
           LexicalCastable<From, std::string>
           LexicalCastable<std::string, To>>::value,
    To>::type
lexicalCast(const From &from)
{
    return lexicalCast<To>(lexicalCast<std::string>(from));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...