小编Nir*_*man的帖子

C++ Nifty Counter习语; 为什么?

我最近遇到了Nifty Counter Idiom.我的理解是,这用于在标准库中实现全局变量,如cout,cerr等.由于专家选择了它,我认为它是一种非常强大的技术.

我试图了解使用更像Meyer Singleton的东西的优势.

例如,人们可以在头文件中:

inline Stream& getStream() { static Stream s; return s; }
static Stream& stream = getStream();
Run Code Online (Sandbox Code Playgroud)

优点是您不必担心引用计数,放置新的,或者有两个类,即代码更简单.既然没有这样做,我肯定有一个原因:

  1. 这是不是保证在共享和静态库中只有一个全局对象?似乎ODR应该保证只能有一个静态变量.
  2. 是否有某种性能成本?看起来在我的代码和Nifty Counter中,你都遵循一个引用来获取对象.
  3. 是否存在引用计数实际有用的情况?看起来它仍然会导致正在构造的对象,如果包含头部,并在程序结束时销毁,如Meyer Singleton.
  4. 答案是否涉及手动dlopen'ing?我对此没有太多经验.

编辑:在阅读Yakk的答案时,我被提示编写以下代码,我将其作为快速演示添加到原始问题中.这是一个非常小的例子,展示了如何使用Meyer Singleton +全局引用在main之前进行初始化:http://coliru.stacked-crooked.com/a/a7f0c8f33ba42b7f.

c++ singleton static-initialization c++11

26
推荐指数
2
解决办法
2518
查看次数

为什么`std :: byte`是枚举类而不是类?

std::byte是一个抽象,它应该提供对C++内存区域的类型安全(r)访问,从新标准17开始.但是,它是根据http://en.cppreference.com/w/cpp这样声明的./ types/byte:

enum class byte : unsigned char {} ;
Run Code Online (Sandbox Code Playgroud)

也就是说,它enum class 没有任何枚举.由于通常的目的enums是提供一组有限的枚举,这似乎有点奇怪.具有私有unsigned char成员的类似乎是更明显的方法.

为什么这样做?

c++ c++-standard-library c++17

18
推荐指数
1
解决办法
854
查看次数

联合公共初始序列与原始

我试图更好地理解关于联合和共同的初始序列规则的相当令人惊讶的发现.常见的初始序列规则是(class.mem 23):

 在具有struct类型T1的活动成员的标准布局并集中,允许读取结构类型T2的另一个union成员的非静态数据成员m,前提是m是T1和T2的公共初始序列的一部分; 行为就像提名T1的相应成员一样.

所以,给定:

struct A {
  int a;
  double x;
};

struct B {
  int b;
};

union U {
  A a;
  B b;
};

U u;
u.a = A{};
int i = u.b.b;
Run Code Online (Sandbox Code Playgroud)

这是定义的行为,i应该具有值0(因为A并且B具有第一个成员的CIS,a int).到现在为止还挺好.令人困惑的是,如果B被简单的int替换:

union U {
  A a;
  int b;
};

...
int i = u.b;
Run Code Online (Sandbox Code Playgroud)

根据常见初始序列的定义:

两种标准布局结构类型的通用初始序列是......

所以CIS只能在两个标准布局结构之间应用.反过来:

标准布局结构是使用类键结构或类键类定义的标准布局类.

所以原始类型肯定不符合条件; 也就是说它没有任何CIS,所以A没有CIS int.因此标准说第一个例子是定义的行为,但第二个例子是UB.这对我来说根本没有任何意义; 直觉上,编译器至少受原始类型和类的限制.如果这是故意的,是否有任何押韵或理由(可能是对齐相关的)为什么这是有意义的?这可能是一个缺陷吗?

c++ unions language-lawyer c++11 c++14

17
推荐指数
1
解决办法
723
查看次数

通过值传递的积分常数,被视为constexpr?

虽然我之前使用过这样的代码,但很明显编译器有足够的信息可以工作,但我真的不明白为什么这会编译:

template <class T, class I>
auto foo(const T& t, I i) {
    return std::get<i>(t);
}

int main()
{
    std::cerr << foo(std::make_tuple(3,4), std::integral_constant<std::size_t, 0>{});
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

实例:http://coliru.stacked-crooked.com/a/fc9cc6b954912bc5.

似乎可以同时使用gcc和clang.的事情是,同时integral_constant具有constexpr转换所存储的整数,constexpr成员函数隐式地把对象本身作为参数,并且因此不能被用在这样的函数constexpr的上下文,除非我们正在呼叫的成员函数的对象本身可以作为被处理constexpr.

这里i是一个传递给的参数foo,因此i绝对不能被视为constexpr.然而,确实如此.一个更简单的例子:

template <class I>
void foo(I i) {
    constexpr std::size_t j = i;
}
Run Code Online (Sandbox Code Playgroud)

这也是编译,只要std::integral_constant<std::size_t, 0>{}传递给foo.

我觉得我错过了一些关于constexpr规则的明显内容.无状态类型或其他类型是否有例外?(或者,也许是两个主要编译器中的编译器错误?这个代码似乎适用于clang 5和gcc 7.2).

编辑:答案已经发布,但我认为这还不够.特别是,鉴于最后的定义foo,为什么:

foo(std::integral_constant<std::size_t, …
Run Code Online (Sandbox Code Playgroud)

c++ templates constexpr c++14

17
推荐指数
2
解决办法
1197
查看次数

为什么将std :: vector和std :: string的比较运算符定义为模板函数?

一点概述.我正在编写一个提供强大typedef的类模板; 通过强类型定义我与一个只声明别名的常规typedef形成对比.提出一个想法:

using EmployeeId = StrongTypedef<int>;
Run Code Online (Sandbox Code Playgroud)

现在,强类型定义和隐式转换有不同的思想流派.其中一所学校说:并非每个整数都是EmployeeId,但每个EmployeeId都是一个整数,所以你应该允许从EmployeeId到整数的隐式转换.你可以实现这个,并编写如下内容:

EmployeeId x(4);
assert(x == 4);
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为x隐式转换为整数,然后使用整数相等比较.到现在为止还挺好.现在,我想用一个整数向量来做这个:

using EmployeeScores = StrongTypedef<std::vector<int>>;
Run Code Online (Sandbox Code Playgroud)

所以我可以这样做:

std::vector<int> v1{1,2};
EmployeeScores e(v1);
std::vector<int> v2(e); // implicit conversion
assert(v1 == v2);
Run Code Online (Sandbox Code Playgroud)

但我还是不能这样做:

assert(v1 == e);
Run Code Online (Sandbox Code Playgroud)

这不起作用的原因是因为如何std::vector定义其等式检查,基本上(模数标准):

template <class T, class A>
bool operator==(const vector<T,A> & v1, const vector<T,A> & v2) {
...
}
Run Code Online (Sandbox Code Playgroud)

这是一个功能模板; 因为它在早期的查找阶段被丢弃,所以不允许将隐式转换为vector的类型进行比较.

定义平等的另一种方式是这样的:

template <class T, class A = std::allocator<T>>
class vector {
... // body

  friend bool operator==(const vector & v1, const vector …
Run Code Online (Sandbox Code Playgroud)

c++ templates vector c++11

14
推荐指数
1
解决办法
654
查看次数

部分专业结构vs重载功能模板

众所周知,函数模板不能部分专门用于C++.当您在概念上尝试实现此目标时,您可以使用两种可能的解决方案.其中一个是使用带有静态函数的结构,可选地用模板函数包装,如下所示:

template <class T, class U>
struct BarHelper
{
    static void BarHelp(T t, const U& u)
    {
        std::cerr << "bar general\n";
    }
};

template <class T>
struct BarHelper<T, double>
{
    static void BarHelp(T t, const double& u)
    {
        std::cerr << "bar specialized\n";
    }
};
template <class T, class U>
void bar(T t, const U& u)
{
    BarHelper<T, U>::BarHelp(t, u);
};
Run Code Online (Sandbox Code Playgroud)

bar 这里是可选的,你可以直接使用结构的静态成员(尽管你必须明确指定所有参数).

另一种方法是重载函数模板:

template <class T, class U>
void func(T t, const U& u)
{
    std::cerr << "func general\n";

} …
Run Code Online (Sandbox Code Playgroud)

c++ templates overload-resolution c++11

12
推荐指数
1
解决办法
538
查看次数

为满足条件的类专门化 `std::hash`

假设我有一个简单的布尔特征类MyTrait. 也就是说,对于任何类型T,我都可以做MyTrait<T>::value并得到正确或错误的结果。我想专门std::hash为各类T地方MyTrait<T>::value是真实的。有没有办法做到这一点?一些失败的尝试:

template <class T, typename std::enable_if<
                                MyTrait<T>::value, int
                            >::type = 0>
struct hash<T> {
...
}
Run Code Online (Sandbox Code Playgroud)

失败,因为:

error: default template argument in a class template partial specialization
Run Code Online (Sandbox Code Playgroud)

我还尝试将所有部分专业化的东西放在哈希之后,但随后会出现一条错误消息,说明T处于非推导的上下文中。

有没有办法做到这一点?至少有一个关于 SO 的先前问题表明没有:将std::hash 专门化为派生类

一个解决方案,或者一个明确的“否”,然后是一个简短的解释,都是一个很好的答案。

c++ templates c++11

10
推荐指数
1
解决办法
857
查看次数

闭包:什么是好用例?为什么不是仿函数?是否值得消极?

我最近潜入Python.以前,我用C++和Matlab编写了大部分数值和数据分析代码.我看到了很多关于Python和Ruby以及闭包的讨论.几乎所有的例子都是这样的:

>>> def makeAdder(y):
...  def myAdder(x):
...   return x + y
...  return myAdder
... 
>>> f = makeAdder(10)
>>> f(5)
15
Run Code Online (Sandbox Code Playgroud)

我知道这在某种意义上是有用的.但是,实际上,在这种情况下("只读"情况)的行为可以很容易地被对象(仿函数)模拟:

>>> class MyAdder(object):
...  def __init__(self,y):
...   self.y = y
...  def __call__(self,x):
...   return self.y + x
... 
>>> f = MyAdder(5)
>>> f(10)
15
Run Code Online (Sandbox Code Playgroud)

该对象不会占用更多的代码空间,而且它的用途更广泛.跟踪和调试后续代码也更容易.

在这种情况下,我们只读取非局部变量.但是我们也可以写它:在Ruby中,当然,在Python中使用nonlocal关键字.当然,对象也支持它.但是对于该对象,您将数据捆绑在一起,这样您就可以准确地知道发生了什么.闭包可能以完全不透明的方式携带变量,这可能导致代码难以调试.这是一个非常奇怪的例子:

irb(main):001:0> def new_counter
irb(main):002:1> x = 0
irb(main):003:1> lambda { x +=1 }
irb(main):004:1> end
=> nil
irb(main):005:0> counter_a = new_counter
=> #<Proc:0x00007f85c6421cd0@(irb):3>
irb(main):006:0> counter_a.call
=> 1
irb(main):007:0> …
Run Code Online (Sandbox Code Playgroud)

ruby python closures functor

8
推荐指数
1
解决办法
3815
查看次数

部分模板专业化和icc

请考虑以下代码:

template <class T, class U, class V>
struct Foo { };

template <class T, class U>
struct Foo<T, U, std::integral_constant<int, U::value>> {
  static void print()
  {
    std::cerr << "instantiated";
  }
};

template <class U>
struct Foo<double, U, std::integral_constant<int, U::value>> {
  static void print()
  {
    std::cerr << "instantiated special";
  }
};

struct Bar {
  static const int value = 0;
};

int main(int argc, char ** argv)
{
  using Baz = Foo<double, Bar, std::integral_constant<int, 0>>;
  Baz::print();

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

当我使用icc …

c++ templates c++11

6
推荐指数
1
解决办法
141
查看次数

非递归 DFS 实现

最近我需要实现非递归 DFS 作为更复杂算法的一部分,准确地说是 Tarjan 算法。递归实现非常优雅,但不适用于大图。当我实现迭代版本时,我对它最终变得多么不优雅感到震惊,我想知道我是否做错了什么。

迭代 DFS 有两种基本方法。首先,您可以一次将一个节点的所有子节点压入堆栈(这似乎更为常见)。或者你可以只推一个。我将专注于第一个,因为这似乎每个人都是这样做的。

我在这个算法上遇到了各种问题,最终我意识到要高效地完成它,我不需要 1 个,不是 2 个,而是 3 个布尔标志(我不一定意味着您需要三个显式布尔变量,您可能会间接存储信息通过变量的特殊值,通常是整数,但您需要以一种或另一种方式访问​​这 3 条信息。这三个标志是:1)已访问。这是为了防止孩子被非常冗余地推入堆栈。2)完成。防止同一节点的冗余处理。3) 升序/降序。指示子项是否已被推入堆栈。伪代码如下所示:

while(S)
    if S.peek().done == True
        S.pop()
        continue

    S.peek().visited = True

    if S.peek().descending == True
        S.peek().descending = False
        for c in S.peek().children
            if c.visited == False
                S.push(c)
        doDescendingStuff()    
    else
        w = S.pop()
        w.done = True
        doAscendingStuff()
Run Code Online (Sandbox Code Playgroud)

一些注意事项:1)从技术上讲,您不需要升/降,因为您可以只查看孩子是否都完成了。但它在密集图中效率很低。

2),主要问题:访问/完成的事情似乎没有必要。这就是为什么(我认为)你需要它。在访问堆栈之前,您无法标记访问过的事物。如果这样做,您可能会以错误的顺序处理事情。例如,假设 A 链接到 B 和 C,B 链接到 D,D 链接到 C。然后从 A,您将 B 和 C 压入堆栈。从 B 将 D 压入堆栈……然后呢?如果在将它们压入堆栈时标记已访问的事物,则不会在此处将 C 压入堆栈。但这是错误的,应该从 D 访问 C,而不是从图中的 A 访问(假设 …

iteration algorithm depth-first-search non-recursive

5
推荐指数
1
解决办法
5532
查看次数