在我的项目中,我使用Boost.Bimap来实现双向映射。
看看Godbolt 上这个非常简单的 MCVE,我在其中使用结构化绑定来打印正确映射的键值对(根据文档,它与std::map
.
问题
它对于任何 g++ 版本 >= 7.4 及更高版本都可以正常编译,但是我需要使用 g++ 7.1。在这里,此代码失败并显示以下消息:
<source>: In function 'int main()':
<source>:11:20: error: 'std::tuple_size<const boost::bimaps::relation::structured_pair<boost::bimaps::tags::tagged<const long unsigned int, boost::bimaps::relation::member_at::right>, boost::bimaps::tags::tagged<const std::__cxx11::basic_string<char>, boost::bimaps::relation::member_at::left>, mpl_::na, boost::bimaps::relation::mirror_layout>>::value' is not an integral constant expression
for (const auto& [key, value] : bm.right) {
我能够发现这是由于g++ 中的一个错误,该错误似乎已在更高版本中修复。
解决方法尝试(玩具示例,成功)
为了使结构化绑定与我的编译器版本一起工作,我尝试通过专门std::tuple_size
化std::tuple_element
和std::get
. 有关更多信息,请参阅此 cppreference 链接。
为简单起见,我首先用玩具结构成功地尝试了这个。以下是专业,请查看 godbolt.org 上的完整代码:
struct SampleType {
int a = 42;
std::string b = "foo"s;
double c = 3.141;
};
#if (__GNUC__ == 7) && (__GNUC_MINOR__ == 1)
template <std::size_t N>
decltype(auto) get(const ::SampleType& t) {
if constexpr (N==0) return t.a;
else if constexpr (N==1) return t.b;
else return t.c;
}
namespace std {
// Tuple size is 3
template <> struct tuple_size<::SampleType> : std::integral_constant<std::size_t, 3> {};
// Define tuple types
template <std::size_t N> struct tuple_element<N, ::SampleType> {
// Deduce type from get() function template defined above
using type = decltype(::get<N>(std::declval<::SampleType>()));
};
}
#endif
请注意,如果您删除#ifdef
for g++ 7.1.,编译将失败并出现与上述相同的错误 ( ...is not an integral constant expression
)。(有趣:与boost::bimap
仅在 g++ 7.4 及更高版本中编译良好的示例不同,玩具示例已经在 g++ 7.2 中成功)
解决方法尝试(原始示例,不成功)
现在,非常确信我找到了解决方案,我尝试做同样的事情,boost::bimap
但我无助地失败了(在 godbolt.org 上查看):
template <std::size_t N>
decltype(auto) get(const bimap::right_map::value_type& bm) {
if constexpr (N==0) return bm.first;
else if constexpr (N==1) return bm.second;
}
namespace std {
// Tuple size is 2 -> key-value pair
template <> struct tuple_size<bimap::right_map::value_type> : std::integral_constant<std::size_t, 2> {};
// Define tuple types
template <> struct tuple_element<0, bimap::right_map::value_type> { using type = std::string; };
template <> struct tuple_element<1, bimap::right_map::value_type> { using type = std::size_t; };
}
错误消息太长,无法在此处发布(请参阅 Godbolt 输出),但基本上我知道get
编译器不匹配“my”的重载。请注意,出于调试原因,我在我的代码中插入了以下行,以确保我实际上处理的是我的专业领域中的正确类型。
for (const auto& pair : bm.right) {
// Make sure we capture the right type in the specializations above
static_assert(std::is_same<
decltype(pair),
const bimap::right_map::value_type&
>::value);
}
难道我做错了什么?还是这个错误对我的解决方法构成了不可逾越的障碍?