考虑一下片段:
#include <unordered_map>
void foo(const std::unordered_map<int,int> &) {}
int main()
{
foo({});
}
Run Code Online (Sandbox Code Playgroud)
这与GCC 4.9.2失败并显示以下消息:
map2.cpp:7:19: error: converting to ‘const std::unordered_map<int, int>’ from initializer list would use explicit constructor ‘std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::size_type, const hasher&, const key_equal&, const allocator_type&) [with _Key = int; _Tp = int; _Hash = std::hash<int>; _Pred = std::equal_to<int>; _Alloc = std::allocator<std::pair<const int, int> >; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::size_type = long unsigned int; std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::hasher = std::hash<int>; std::unordered_map<_Key, …
Run Code Online (Sandbox Code Playgroud) 我已经使用基于SFINAE的方法已经有一段时间了,特别是通过启用/禁用特定的类模板特化std::enable_if
.
因此,在阅读描述提议的void_t
别名/检测习语的论文时,我有点困惑:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf
第4节专门讨论成语的有效性,并参考了一个讨论,其中两方争论SFINAE在部分类模板专业化中的适用性(理查德史密斯指出该标准缺乏关于该主题的措辞) .在本节末尾,提到了以下CWG问题
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2054
这里再次声明该标准没有明确地允许在该问题中再现的示例.
我有点困惑,因为在我看来,例如,在enable_if
一段时间内使用部分特化已经成为标准做法(例如参见Boost文档,它明确提到了部分特化).
我误解了上述文件中的要点还是真的是灰色区域?
C++标准有时使用短语"不应抛出异常",例如在枚举Hash
要求时在17.6.3.4中.这是否意味着符合标准的实现必须将调用操作符标记为std::hash
as noexcept
或者这是否意味着从散列函数中抛出会导致未定义或实现定义的行为?
我检查了libstdc ++和libc ++标记std::hash
的调用操作符noexcept
,但我想知道这是否是必需的行为.
这在技术上是否正确:
unsigned abs(int n)
{
if (n >= 0) {
return n;
} else {
return -n;
}
}
Run Code Online (Sandbox Code Playgroud)
在我看来,如果-INT_MIN> INT_MAX,"-n"表达式在n == INT_MIN时可能会溢出,因为-INT_MIN超出了边界.但是在我的编译器上,这似乎工作正常......这是一个实现细节还是可以依赖的行为?
更长的版本
一点上下文:我正在为GMP整数类型(mpz_t)编写一个C++包装器,并从现有的GMP C++包装器(称为mpz_class)中获取灵感.当处理带有符号整数的mpz_t时,有如下代码:
static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
{
if (l >= 0)
mpz_add_ui(z, w, l);
else
mpz_sub_ui(z, w, -l);
}
Run Code Online (Sandbox Code Playgroud)
换句话说,如果有符号整数是正数,则使用无符号加法例程添加它,如果有符号整数为负,则使用无符号减法例程添加它.两个*_ui例程都将unsigned long作为最后一个参数.是表达
-l
Run Code Online (Sandbox Code Playgroud)
有溢出的危险吗?
考虑一下:
template <typename T>
struct hash
{
static_assert(false,"Not implemented.");
};
struct unhashable {};
template <typename T>
auto test(const T &t) -> decltype((*(hash<T> const *)nullptr)(t),int);
void test(...);
int main()
{
std::cout << std::is_same<decltype(test(std::declval<unhashable>())),void>::value;
}
Run Code Online (Sandbox Code Playgroud)
除了显然缺少标题,这应该编译吗?
换句话说,我问的是,如果在推断重载函数模板的返回值的同时触发尾随decltype内部的静态断言失败是否要求停止编译,或者是否只是丢弃了重载.
在gcc 4.7上,编译失败.我很积极,虽然这将在gcc 4.8中编译好(但在此刻无法检查).谁是对的?
C++ 11提供了std::allocator_traits
类作为使用分配器的标准方法.static函数std::allocator_traits::construct()
接受指向对象构造位置的指针.的std::allocator_traits::allocate()
静态功能,但是,返回一个allocator::pointer
值,该值仅必须表现得像一个指针,但它不一定是一个(通常,虽然std::allocator::pointer
需要是一个指针).
一般来说,如果它们可以使用不兼容的类型,那么应该如何使用分配和构造静态方法?只有当pointer
类型实际上可以转换为普通的普通指针时才可以使用它们吗?
我希望能够按照以下方式写一些东西:
struct bar {};
template <typename ... Args>
bar operator+(bar, Args ...)
{}
Run Code Online (Sandbox Code Playgroud)
我刚用clang/gcc检查过,重载的运算符被二进制表达式(a+b
)和一元表达式(+a
)所取代,正如我所料.但是,运算符比正常函数更受限制,例如 - 你不能operator+()
用三个参数重载.
以上用法是否合法且便携?
编辑为了给出一些上下文,我显然不希望能够定义可变运算符或任何类型的运算符.我对此感兴趣的原因是一个丑陋的黑客:我想使一些运算符变量,以便我可以用其他非变量实现"覆盖"它们.由于变量模板被认为不如函数模板重载规则中的非可变参数模板专用,我可以使用非可变参数覆盖可变参数运算符.是的,它非常可怕:)
c++ templates operator-overloading language-lawyer variadic-templates
我试图理解为什么一块模板元编程不会产生无限递归.我试图尽可能地减少测试用例,但仍然需要一些设置,所以忍受我:)
设置如下.我有一个泛型函数foo(T)
,它将实现委托给foo_impl
通过其调用运算符调用的泛型函子,如下所示:
template <typename T, typename = void>
struct foo_impl {};
template <typename T>
inline auto foo(T x) -> decltype(foo_impl<T>{}(x))
{
return foo_impl<T>{}(x);
}
Run Code Online (Sandbox Code Playgroud)
foo()
使用decltype尾随返回类型用于SFINAE目的.默认实现foo_impl
不定义任何调用操作符.接下来,我有一个type-trait,它检测是否foo()
可以使用类型的参数调用T
:
template <typename T>
struct has_foo
{
struct yes {};
struct no {};
template <typename T1>
static auto test(T1 x) -> decltype(foo(x),void(),yes{});
static no test(...);
static const bool value = std::is_same<yes,decltype(test(std::declval<T>()))>::value;
};
Run Code Online (Sandbox Code Playgroud)
这只是通过表达式SFINAE的类型特征的经典实现:
has_foo<T>::value
如果foo_impl
存在有效的特化,则为T
true,否则为false.最后,我有两个用于整数类型和浮点类型的实现函子的特化:
template <typename T>
struct …
Run Code Online (Sandbox Code Playgroud) 我花了一些时间仔细阅读标准参考文献,但我无法找到以下答案:
我得到的最接近的是C99标准的第6.2.6.2节(C++的措辞对我来说更加神秘,我认为它们与此相当):
对于有符号整数类型,对象表示的位应分为三组:值位,填充位和符号位.(...)作为值位的每个位应具有与相应无符号类型的对象表示中的相同位相同的值(如果在有符号类型中有M个值位且Nin为无符号类型,则M≤ N).
因此,在假设的4位有符号/无符号整数类型中,是否有任何阻止无符号类型具有1个填充位和3个值位的东西,以及具有3个值位和1个符号位的带符号类型?在这种情况下,无符号的范围是[0,7],对于有符号,它将是[-8,7](假设是2的补码).
如果有人好奇,我现在依赖于一种技术来提取负整数的绝对值,该负整数包括第一个强制转换为无符号对应物,然后应用一元减号运算符(例如 - 3通过强制转换为4,然后通过一元减去3).这将破坏上面的例子-8,它无法用无符号类型表示.
编辑:感谢Keith和Potatoswatter下面的回复.现在,我最后的疑问是关于标准措辞中"子范围"的含义.如果它意味着严格的"小于"包含,那么我上面的例子和下面的Keith不符合标准.如果子范围可能是整个无符号范围,那么它们就是.
我不确定标题是否有意义,但这个例子实际上是非常明确的:
// A converter struct with a generic constructor.
template <template <typename ...> class TT>
struct converter
{
template <typename ... Args>
converter(const TT<Args ...> &);
};
// A few class templates.
template <typename T>
struct foo {};
template <typename T, typename U>
struct foo2 {};
template <typename ... Args>
struct foo_variadic {};
template <typename Arg0, typename ... Args>
struct foo_variadic2 {};
int main()
{
// All these compile.
converter<foo>(foo<int>{});
converter<foo2>(foo2<int,double>{});
converter<foo_variadic>(foo_variadic<>{});
converter<foo_variadic>(foo_variadic<int>{});
converter<foo_variadic>(foo_variadic<int,double>{});
// This will not compile.
// …
Run Code Online (Sandbox Code Playgroud)