我正在做一些C++计算机制(不用担心,这里不需要物理知识)并且有些东西真的困扰我.
假设我想表示一个3D数学向量(与std :: vector无关):
class Vector {
public:
Vector(double x=0., double y=0., double z=0.) {
coordinates[0] = x;
coordinates[1] = y;
coordinates[2] = z;
}
private:
double coordinates[3];
};
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.现在我可以重载operator []来提取坐标:
double& Vector::operator[](int i) {
return coordinates[i] ;
}
Run Code Online (Sandbox Code Playgroud)
所以我可以输入:
Vector V;
… //complex computation with V
double x1 = V[0];
V[1] = coord2;
Run Code Online (Sandbox Code Playgroud)
问题是,从0开始索引在这里并不自然.我的意思是,在排序数组时,我并不介意,但事实是每篇论文,书籍或其他内容中的常规符号总是以1开头的子行程坐标.这可能看起来很狡辩,但事实是在公式中,它总是需要双重理解我们正在采取的措施.当然,对于矩阵来说,这是最糟糕的.
一个明显的解决方案是稍微不同的重载:
double& Vector::operator[](int i) {
return coordinates[i-1] ;
}
Run Code Online (Sandbox Code Playgroud)
所以我可以输入
double x1 = V[1];
V[2] = coord2;
Run Code Online (Sandbox Code Playgroud)
它似乎是完美的,除了一件事:这个i-1减法似乎是一个很小的开销的好候选人.你会说很小,但我正在做计算机制,所以这通常是我们买不起的东西.
所以现在(最后)我的问题是:您认为编译器可以优化它,还是有办法使其优化?(模板,宏,指针或参考kludge ...)
逻辑上,在
double xi = V[i]; …Run Code Online (Sandbox Code Playgroud) 我想传递模板化的函数,好像它们是通用的lambda,但是这不起作用.
#include <iostream>
#include <vector>
#include <tuple>
#include <string>
#include <utility>
// for_each with std::tuple
// (from https://stackoverflow.com/a/6894436/1583122)
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
for_each(std::tuple<Tp...> &, FuncT)
{}
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
for_each(std::tuple<Tp...>& t, FuncT f) {
f(std::get<I>(t));
for_each<I + 1, FuncT, Tp...>(t, f);
}
// my code
template<class T> auto
print(const std::vector<T>& v) -> void {
for (const auto& e : …Run Code Online (Sandbox Code Playgroud) C ++核心准则指出:
F.20:对于“输出”输出值,更喜欢返回值而不是输出参数
但是然后给出以下异常:
struct Package { // exceptional case: expensive-to-move object
char header[16];
char load[2024 - 16];
};
Package fill(); // Bad: large return value
void fill(Package&); // OK
Run Code Online (Sandbox Code Playgroud)
Isn't it supposed to be a case where the return value optimization kicks in ? Is RVO prevented in this case ? Or still not as efficient as passing by reference ? Or is it that some compilers don't manage to do it ?
More generally, when should I rely …
根据C标准:
当两个指针相减时,两者都应指向同一数组对象的元素,或指向数组对象最后一个元素的元素(第 6.5.6 1173 节)
[注意:不要假设我对标准或 UB 了解很多,我只是碰巧发现了这个]
现在另一方面
因此我的问题是:从实验来看,似乎在某些体系结构(例如 x86-64)上,两个数组之间的指针差异提供了合理的、可重现的结果。它似乎与这些架构的硬件相当吻合。那么某些实现是否真的确保了特定的行为?
例如,在野外是否有一个实现可以保证a并且b存在char*,我们有a + (reinterpret_cast<std::ptrdiff_t>(b)-reinterpret_cast<std::ptrdiff_t>(a)) == b?
开门见山:以下安全吗?
vector<int> v;
int const* last = &*v.end();
// last is never dereferenced
Run Code Online (Sandbox Code Playgroud)
我担心的是,从迭代器获取普通旧指针的技巧会强制取消引用 end() 迭代器,这是无效的......即使只是将指针取回!
背景:我正在尝试创建由任意类型(尤其是整数和指向对象的指针)索引的条目集合。
template<class IT>
/// requires IT implements addition (e.g. int, random-access iterator)
class IndexingFamily {
public:
using IndexType = IT;
IndexingFamily(IndexType first, IndexType last);
int size() const;
IndexType operator[](int i) const;
private:
IndexType first;
IndexType last;
};
template<class IT> IndexingFamily<IT>::
IndexingFamily(IndexType first, IndexType last)
: first(first)
, last(last) {}
template<class IT> auto IndexingFamily<IT>::
size() const -> int {
return last-first;
}
template<class IT> …Run Code Online (Sandbox Code Playgroud) C++ 标准要求编译器检查C++ constexpr 计算中未定义的行为。
在这次演讲中,Chandler Carruth 指出,在检查 UB 时“你将耗尽检测错误的能力”,并且在一般情况下,检测 UB 与停机问题有关,因此证明不可能做出决定。
他不是在谈论 constexpr 中的 UB,但constexpr 计算与自 C++14 以来的常规程序一样通用,因此这仍然适用。
那么,当编译器无法确定程序是否是 UB 时,他们会做什么呢?他们是否仍然接受该程序并继续编译?或者他们是否更加保守并拒绝该计划,即使它可能是正确的?(我个人的感觉是他们这样做)
对我来说,这具有实际意义,因为我使用非平凡的指针算术进行了 constexpr 评估,用 Clang 编译得很好,但用 GCC 编译失败,而且我很确定这不是 UB。你可以说这是一个 GCC bug,但是如果 UB 是不可判定的,那么所有编译器在这方面都会存在 bug。
更根本的是,为什么标准要求不含 UB ?有技术原因吗?或者更多的是一种哲学(“如果编译器无法检查,程序员可以触发 UB,就会导致不好的结果”)?
我认为这与 C++ 的其余部分不一致,这永远不会阻止你搬起石头砸自己的脚。我希望 GCC 接受我的 constexpr 代码并崩溃,或者如果 UB 则发出垃圾;而不是在不知道是否是UB的情况下不编译。
====== 编辑======
正如 MM 和 Nicol Bolas 所指出的,该标准指定了限制(即使在 C++14 中也是如此),因此我们永远不会陷入 UB 的停止问题类型。然而,我仍然想知道检查 UB 是否可能太复杂,并且如果编译器启发式失败,那么它们会将其标记为非 constexpr(可能是错误的)。
但从评论中我感觉这更多是一个不成熟的实现问题。
以下程序编译为 C 程序:
\n#include <stdlib.h>\n#include <stdio.h>\n\nvoid f(int n, int m, int x[n][m]) {\n printf("x[0][2] = %i\\n",x[0][2]);\n}\n\nint main() {\n int v[][3] = { {0,1,2}, {3,4,5} };\n\n f(2,3,v);\n}\nRun Code Online (Sandbox Code Playgroud)\n然而,当用 g++ 编译为 C++ 时,我有:
\nmain.c:4:29: error: use of parameter outside function body before \xe2\x80\x98]\xe2\x80\x99 token\n void f(int n, int m, int x[n][m]) {\n ^\nRun Code Online (Sandbox Code Playgroud)\n看来C的这个特性在C++中并不存在。是否可以向 g++ 提供任何标志以使其接受代码?
\n我有一个复杂的C++对象,我想在我的Fortran代码中使用它.通常,从Fortran调用C++代码没有问题(例如,只需要提供一个带有C链接的合适接口).
但是我的问题是我希望我对C++的Fortran调用能够操作我称之为持久对象的东西:由第一个init函数创建的C++对象,并由其他C++函数操作.
更具体地说,假设我有以下C++代码
struct A {
public:
void do() { // do something on complicated stuff
private:
... // complicated stuff
};
extern "C" {
void* init_A() {
A* a = new A();
return reinterpret_cast<void*>(a);
}
void doSth(void* ptr_to_A) {
A* a = reinterpret_cast<A*>(ptr_to_A);
a.do();
}
void teardown_A(void* ptr_to_A) {
A* a = reinterpret_cast<A*>(ptr_to_A);
delete a;
}
}
Run Code Online (Sandbox Code Playgroud)
以下fortran代码(假设它是main()):
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR
INTERFACE
TYPE(C_PTR) FUNCTION init_A() BIND(C, NAME='init_A')
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR
IMPLICIT NONE
END …Run Code Online (Sandbox Code Playgroud) 我试图理解完美转发和构造函数的相互作用.我的例子如下:
#include <utility>
#include <iostream>
template<typename A, typename B>
using disable_if_same_or_derived =
std::enable_if_t<
!std::is_base_of<
A,
std::remove_reference_t<B>
>::value
>;
template<class T>
class wrapper {
public:
// perfect forwarding ctor in order not to copy or move if unnecessary
template<
class T0,
class = disable_if_same_or_derived<wrapper,T0> // do not use this instead of the copy ctor
> explicit
wrapper(T0&& x)
: x(std::forward<T0>(x))
{}
private:
T x;
};
class trace {
public:
trace() {}
trace(const trace&) { std::cout << "copy ctor\n"; }
trace& operator=(const …Run Code Online (Sandbox Code Playgroud)