C++标准在<cmath>头文件中定义了一些不属于<math.h>C中头部的重载函数(因为C没有重载).其中有float abs(float),double abs(double),long double abs(long double),和double abs(Integral).另一方面,absC <math.h>中根本没有定义(<stdlib.h>相反),唯一的签名是int abs(int).
现在在我的系统上,当使用带有C++程序的C++编译器时,#include <math.h>不会abs在全局命名空间或中提供C++ 重载std.另一方面,#include <cmath>定义std::abs.
这是我所期望的 - 包括C版本以获取C函数,并包含C++版本以获得C++函数.@visitor的回答提到了同样的事情.
但是,用户@ Cheers-and-hth-Alf坚持认为这违反了标准,因为它说"每个C头,每个都有一个表单的名称name.h,就像每个名称放在标准库名称空间中一样通过相应的cname头放在全局命名空间范围内." (本节D.5.2在C++ 03,C++ 11和C++ 14之间似乎没有太大变化.)
检查你的平台做什么很容易:看看会发生什么
#include <math.h>
int main() {
abs(1.2);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果abs未声明,<math.h>则不包括C++函数.
如果它编译,然后尝试包括<stdio.h>
并添加printf("%g\n", abs(1.2));
如果这抱怨格式不匹配,或打印1,则<math.h>
包括C …
考虑:
unsigned foo(unsigned u) {
return u;
}
int main() {
foo(-1);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在这里,函数foo被调用u等于4294967295(或类似的大值.)如果程序员没有注意,这可能是非常意外的.
例如,您可能正在实施pow将Polynomial类提升为幂.由于只有正权力,您可以决定签名
Polynomial pow(const Polynomial& p, unsigned exp);
Run Code Online (Sandbox Code Playgroud)
然后一个粗心的程序员调用pow(p, -1)得到一个逆,而不是一个警告或错误,它似乎工作,但可能使用极大的内存和时间来产生一个完全错误的答案.
g ++ 5.3.0和gcc 5.3.0,无需投诉即可编译-Wall -Wextra.
他们将警告它的选项-Wsign-conversion,但是这发出警告每次从转换int到unsigned并迅速太烦人(它警告每次指数与一个载体int,vec[i]等.)
gcc可以警告将负文字或其他负编译时常量作为无符号参数传递吗?
我编写了一个RandIt类(下面的代码),它的作用类似于迭代器,但只要取消引用就会返回随机整数.主要用例是使用随机数据初始化向量,如
std::vector<int> v(RandIt<0,99>{}, RandIt<0,99>{50});
Run Code Online (Sandbox Code Playgroud)
生成0到99之间的50个数字.
typedef RandIt::iterator_category是std::random_access_iterator_tag因为
std::distance.否则emplace_back使用,重新分配和复制.std::distance才能保持恒定时间,而不是在循环中递增和测试.但是,这是一个谎言,因为取消引用RandIt会返回一个intby值,并且ForwardIterators和better都需要返回对内存中对象的引用.
(由于ForwardIterator的"多通道保证"失败,这也可能是一个谎言:再次检查序列会产生不同的结果.但是cppreference给出了"正式"版本
表达式
(void)++It(a), *a等同于表达式*a
这似乎是真的,对于某些"等价"的值.)
因此,我绝对违反了规则,声称自己不是.尽管如此,它似乎有效.
这会咬我吗?说谎的潜在影响是什么?
#include <random>
#include <iterator>
template <int min, int max>
struct RandIt {
typedef int difference_type;
typedef int value_type;
typedef const int* pointer;
typedef const int& reference;
typedef std::random_access_iterator_tag iterator_category; // this is a lie
static std::knuth_b rng;
static std::uniform_int_distribution<int> idist;
int i;
explicit RandIt(int i = 0) : …Run Code Online (Sandbox Code Playgroud) 假设我有一个程序使用boost :: program_options来解析命令行参数,并且有一个unsigned值:
#include <boost/program_options.hpp>
#include <iostream>
namespace po = boost::program_options;
int main(int argc, char* argv[]) {
unsigned num;
po::options_description desc;
desc.add_options()
("num,n", po::value<unsigned>(&num), "Non-negative number");
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
std::cout << "Number: " << num << '\n';
return 0;
}
Run Code Online (Sandbox Code Playgroud)
然后,如果我在命令行上传递一个负值,它会接受它并将其包装起来:
$ ./bponeg -n -1 Number: 4294967295
我宁愿负数会触发错误(即抛出invalid_option_value),就像我写的那样./bponeg -n abc.在解析之后,从我自己的代码中,似乎无法区分用户编写的情况-1或他们写的情况4294967295.
我可以指示program_options解析器拒绝unsigned值的负输入吗?
我在这里讲述一个长篇大论的背景故事,因为除了直接回答之外,我想知道导致这种情况的推理是否正确.
我有一个带dynamic_bitset<>参数的函数(来自Boost.dynamic_bitset).说它看起来像这样.
void foo(boost::dynamic_bitset<> db) {
// do stuff
}
Run Code Online (Sandbox Code Playgroud)
碰巧它只是用构造函数构建的临时函数foo(boost::dynamic_bitset<>{5}.set())调用,如同(用5位bitset调用所有位设置).
我的位集只有少量位(少于32位).所以起初,我想"我只是按值传递它;副本比指针小." 但后来我想"它是动态的,所以它必须在堆上分配空间.我想避免不必要的分配和释放."
所以,我可以做到
void foo(const boost::dynamic_bitset<>& db);
Run Code Online (Sandbox Code Playgroud)
但是引用是一个指针,而dynamic_bitset(可能)有一个指向其数据的指针,因此使用dbwithin foo会经历两个间接级别,这看起来很愚蠢.显然,最好的方法是将指针复制到数据中foo,而无需重新分配和复制堆上的数据.
"啊哈!" 我说."当然这就是语义学的用途." 所以,我将签名更改为
void foo(boost::dynamic_bitset<>&& db);
Run Code Online (Sandbox Code Playgroud)
但是,调用foo(boost::dynamic_bitset<>{5}.set())会产生编译错误cannot bind 'boost::dynamic_bitset<>' lvalue to 'boost::dynamic_bitset<>&&'.我必须打电话
foo(std::move(boost::dynamic_bitset<>{5}.set()))
然后一切正常.
为什么我需要调用std :: move? 这似乎显然是一个xvalue(临时即将到期),不是吗?
在Go 编程语言的第 308 页上,它说
名为 main 的包通常会生成可执行程序,但它也可以作为库导入。
但是当我尝试时,我收到一个错误:imp.go:5:5: import "foo" is a program, not an importable package
那么……他们在说什么?如何将主包导入为库?
我的试用代码只是:
imp.go
package main
import (
"fmt"
"foo"
)
func main() {
fmt.Println(foo.Hi)
}
Run Code Online (Sandbox Code Playgroud)
foo/foo.go
package main
import "fmt"
var Hi int = 3
func main() {
fmt.Printf("Hi %d!\n", Hi)
}
Run Code Online (Sandbox Code Playgroud)