使用非类型模板和空 lambda 时,静态断言因无序映射而失败
static assertion failed with unordered map when using non-type template and empty lambda
以下 class 将在 std::map 内触发静态断言错误,因为分配器的 value_type
不同,尽管分配器是默认的:
template < bool store>
class MyClass {
public:
using hashmap_type = std::unordered_map<
int,
decltype([](){})
>;
private:
std::map< int, hashmap_type > m_mapofmaps;
};
通过 Myclass<false> v{};
触发器使用它
/opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/bits/hashtable.h:191:21: error: static assertion failed: unordered container must have the same value_type as its allocator
191 | static_assert(is_same<typename _Alloc::value_type, _Value>{},
可以看出here (GCC 11.1):
但是如果删除非类型模板 store
,编译器突然就没有问题了。这同样适用于将 lambda [](){}
与另一种类型交换,参见 here and here.
布尔非类型模板、lambda 和分配器之间的奇怪相互作用是什么?
似乎是 gcc 如何将默认参数替换为涉及未评估的 lambda 类型的模板参数的错误。
类似的例子:
#include <type_traits>
template<typename T, typename U = T>
struct assert_is_same {
static_assert(std::is_same_v<T, U>);
};
template<bool B>
struct X {
assert_is_same<decltype([](){})> x;
};
int main() {
X<false> a;
}
如果没有 template<bool B>
,decltype([](){})
不是依赖表达式,因此会更急切地求值(最终会得到类似 assert_is_same<_ZN1XILb0EEUlvE0_E, _ZN1XILb0EEUlvE0_E>
的结果)
在模板中,[](){}
的类型现在依赖于 B
,因此无法立即替换为类型。似乎 gcc 将其扩展为 assert_is_same<decltype([](){}), decltype([](){})>
,这两个 lambda 现在不同了。 (地图示例中的默认参数是 std::allocator<std::pair<const Key, T>>
,或 std::allocator<std::pair<const int, decltype([](){})>>
)
一个解决方法是给 lambda 一个可以隐藏的名字:
private:
static constexpr auto lambda = [](){};
public:
using hashmap_type = std::unordered_map<
int,
decltype(lambda)
>;
// allocator is now `std::pair<const int, decltype(lambda)>`, and
// the two `decltype(lambda)`'s have the same type
以下 class 将在 std::map 内触发静态断言错误,因为分配器的 value_type
不同,尽管分配器是默认的:
template < bool store>
class MyClass {
public:
using hashmap_type = std::unordered_map<
int,
decltype([](){})
>;
private:
std::map< int, hashmap_type > m_mapofmaps;
};
通过 Myclass<false> v{};
触发器使用它
/opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/bits/hashtable.h:191:21: error: static assertion failed: unordered container must have the same value_type as its allocator
191 | static_assert(is_same<typename _Alloc::value_type, _Value>{},
可以看出here (GCC 11.1):
但是如果删除非类型模板 store
,编译器突然就没有问题了。这同样适用于将 lambda [](){}
与另一种类型交换,参见 here and here.
布尔非类型模板、lambda 和分配器之间的奇怪相互作用是什么?
似乎是 gcc 如何将默认参数替换为涉及未评估的 lambda 类型的模板参数的错误。
类似的例子:
#include <type_traits>
template<typename T, typename U = T>
struct assert_is_same {
static_assert(std::is_same_v<T, U>);
};
template<bool B>
struct X {
assert_is_same<decltype([](){})> x;
};
int main() {
X<false> a;
}
如果没有 template<bool B>
,decltype([](){})
不是依赖表达式,因此会更急切地求值(最终会得到类似 assert_is_same<_ZN1XILb0EEUlvE0_E, _ZN1XILb0EEUlvE0_E>
的结果)
在模板中,[](){}
的类型现在依赖于 B
,因此无法立即替换为类型。似乎 gcc 将其扩展为 assert_is_same<decltype([](){}), decltype([](){})>
,这两个 lambda 现在不同了。 (地图示例中的默认参数是 std::allocator<std::pair<const Key, T>>
,或 std::allocator<std::pair<const int, decltype([](){})>>
)
一个解决方法是给 lambda 一个可以隐藏的名字:
private:
static constexpr auto lambda = [](){};
public:
using hashmap_type = std::unordered_map<
int,
decltype(lambda)
>;
// allocator is now `std::pair<const int, decltype(lambda)>`, and
// the two `decltype(lambda)`'s have the same type