从 MSVC2015 更新 2 移植到 GCC 5.3 - SFINAE 错误
Porting from MSVC2015 Update 2 to GCC 5.3 - SFINAE Errors
我目前正在移植我的库,但我的黑暗模板魔术无法使用 GCC 5.3 进行编译
此片段在使用 MSVC2015 更新 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 was not defined in current scope (WTF?)"
到目前为止我尝试过的:
将上面的模板片段重写为
template<typename vreal,
typename enable = typename std::enable_if<std::is_vreal<vreal>::value != 0>::type>
但这也不管用。它在代码中中断了很久,我认为这是由于引入了额外的模板参数。
此外,我不明白为什么我必须引入与 0 的比较。如果没有它,gcc 会抱怨 enabled_if 上缺少 'type'。
所以,主要问题是:如何在没有额外参数的情况下获得相同的 SFINAE 逻辑(仅当参数为 vreal 时才编译)。
我可以将其重写为 return 类型 SFINAE - 但我想避免做很多工作(区分函数、类、结构、类型定义/使用。 ..) 即使它被包裹在宏中。
template<typename vreal>
typename std::enable_if<is_vreal<vreal>, vreal>::type inline vreal .....
对于你的顶级函数,你可以这样:
template<typename vreal>
inline typename std::enable_if<std::is_vreal<vreal>::value, floatType>::type foo(vreal bar)
{
return bar;
}
您的结构也应该重新定义。下面的解决方案无法摆脱在此处使用次要参数 Enable 的部分特化:
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
并特化一个基础 class。
看起来像这样:
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 命名空间中注入东西,编译器可以自由拒绝它。
这不是有效的 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
(您 post 是 [MCVE] 对吗?)。在 vreal
.
的定义中,它在范围内之前使用 vreal
我不知道它应该是什么意思,除了你似乎相信它有 SFINAE 魔法:它指出如果 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 helper。
完全放弃宏。 Class 和函数模板的工作方式有很大不同。
对于classes/structs:
template<class vreal>
struct bar { vreal i; };
因为确实没有另一种选择 - 没有像函数那样用 structures/classes 重载的概念。
对于函数,我们需要 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;
}
如果函数 returns 是不同类型,则执行
template<class vreal>
inline vreal_test<vreal,void> foo2(vreal bar)
{
return;
}
您可以在清除宏时执行此操作。
我目前正在移植我的库,但我的黑暗模板魔术无法使用 GCC 5.3 进行编译
此片段在使用 MSVC2015 更新 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 was not defined in current scope (WTF?)"
到目前为止我尝试过的:
将上面的模板片段重写为
template<typename vreal,
typename enable = typename std::enable_if<std::is_vreal<vreal>::value != 0>::type>
但这也不管用。它在代码中中断了很久,我认为这是由于引入了额外的模板参数。
此外,我不明白为什么我必须引入与 0 的比较。如果没有它,gcc 会抱怨 enabled_if 上缺少 'type'。
所以,主要问题是:如何在没有额外参数的情况下获得相同的 SFINAE 逻辑(仅当参数为 vreal 时才编译)。
我可以将其重写为 return 类型 SFINAE - 但我想避免做很多工作(区分函数、类、结构、类型定义/使用。 ..) 即使它被包裹在宏中。
template<typename vreal>
typename std::enable_if<is_vreal<vreal>, vreal>::type inline vreal .....
对于你的顶级函数,你可以这样:
template<typename vreal>
inline typename std::enable_if<std::is_vreal<vreal>::value, floatType>::type foo(vreal bar)
{
return bar;
}
您的结构也应该重新定义。下面的解决方案无法摆脱在此处使用次要参数 Enable 的部分特化:
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
并特化一个基础 class。
看起来像这样:
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 命名空间中注入东西,编译器可以自由拒绝它。
这不是有效的 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
(您 post 是 [MCVE] 对吗?)。在 vreal
.
vreal
我不知道它应该是什么意思,除了你似乎相信它有 SFINAE 魔法:它指出如果 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 helper。
完全放弃宏。 Class 和函数模板的工作方式有很大不同。
对于classes/structs:
template<class vreal>
struct bar { vreal i; };
因为确实没有另一种选择 - 没有像函数那样用 structures/classes 重载的概念。
对于函数,我们需要 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;
}
如果函数 returns 是不同类型,则执行
template<class vreal>
inline vreal_test<vreal,void> foo2(vreal bar)
{
return;
}
您可以在清除宏时执行此操作。