无限模板递归,因为仅使用 gcc 没有 bool 表达式优化
Infinite template recursion because no bool expression optimisation only with gcc
我正在研究一个词法施法者。请参阅下面代码中简化的、有问题的部分。该代码使用 clang 和 msvc 编译,但无法使用 gcc 编译。看起来,在 lexicalCast 的 std::enable_if
的第一个参数中,gcc 尝试在评估之前评估 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{});
~~~~~~~~~~~~~~~~~~^~
how can I solve this problem to be able to compile this code with 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));
}
我正在研究一个词法施法者。请参阅下面代码中简化的、有问题的部分。该代码使用 clang 和 msvc 编译,但无法使用 gcc 编译。看起来,在 lexicalCast 的 std::enable_if
的第一个参数中,gcc 尝试在评估之前评估 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{});
~~~~~~~~~~~~~~~~~~^~
how can I solve this problem to be able to compile this code with 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));
}