标签: c++14

错误:不合时宜的旧式基类初始化程序

以下代码在C++ 98,C++ 11和C++ 14模式下对我尝试的所有GCC版本产生后续编译错误:

struct T
{
    T(void* x) : (x) {}
};

// main.cpp: In constructor 'T::T(void*)':
// main.cpp:3:18: error: anachronistic old-style base class initializer [-fpermissive]
//      T(void* x) : (x) {}
//                   ^
// main.cpp:3:16: error: unnamed initializer for 'T', which has no base classes
//      T(void* x) : (x) {}
Run Code Online (Sandbox Code Playgroud)

当然,它显然是破碎的代码,因为我实际上并没有初始化任何东西.

但为什么它是基类初始化器,为什么它是"不合时宜的",而不是简单的错误?曾经有效吗?什么时候?这是什么意思?


我在网上找到的唯一的相关参考文献是,当一个成员名称被意外地宏出时,人们遇到了错误,实际上产生了与上面相同的代码:

#define bar
// ^ some library could have done this

struct T
{
    T(int x)
        : bar(x)   // effectively just `: …
Run Code Online (Sandbox Code Playgroud)

c++ gcc c++11 c++03 c++14

49
推荐指数
3
解决办法
3852
查看次数

为什么在C++ 14中不推荐使用std :: shuffle方法?

根据std :: shufle上的cppreference.com参考站点,在c ++ 14中不推荐使用以下方法:

template< class RandomIt >
void random_shuffle( RandomIt first, RandomIt last );
Run Code Online (Sandbox Code Playgroud)

为什么我们不再能够在不传递第三个参数的情况下调用以下函数?

std::random_shuffle(v.begin(),v.end()); //no longer valid in c++14
Run Code Online (Sandbox Code Playgroud)

看起来好像不同的功能减速具有默认参数设置.这背后的原因是什么?是否添加了某种替代方案?

c++ deprecated stl-algorithm c++11 c++14

48
推荐指数
5
解决办法
8378
查看次数

通过价值传递与通过右值参考传递

我什么时候应该声明我的功能:

void foo(Widget w);

而不是

void foo(Widget&& w);

假设这是唯一的重载(例如,我选择一个或另一个,不是两个,也没有其他重载).没有涉及模板.假设该函数foo需要所有权Widget(例如const Widget&,不是本讨论的一部分).我对这些情况范围之外的任何答案都不感兴趣.请参阅帖子末尾的附录,了解为什么这些约束是问题的一部分.

我和我的同事可以提出的主要区别是rvalue参考参数强制您明确复制副本.调用者负责制作一个显式副本,然后在std::move需要副本时将其传入.在按值传递的情况下,隐藏了副本的成本:

    //If foo is a pass by value function, calling + making a copy:
    Widget x{};
    foo(x); //Implicit copy
    //Not shown: continues to use x locally

    //If foo is a pass by rvalue reference function, calling + making a copy:
    Widget x{};
    //foo(x); //This would be a compiler error
    auto copy = x; //Explicit copy
    foo(std::move(copy));
    //Not shown: continues …
Run Code Online (Sandbox Code Playgroud)

c++ c++11 c++14

48
推荐指数
5
解决办法
2万
查看次数

实现C++ 14 make_integer_sequence

我尝试实现C++ 14别名模板make_integer_sequence,这简化了类模板的创建integer_sequence.

template< class T, T... I> struct integer_sequence
{
    typedef T value_type;
    static constexpr size_t size() noexcept { return sizeof...(I) ; }

};

template< class T, T N>
using make_integer_sequence = integer_sequence< T, 0,1,2, ... ,N-1 >; // only for illustration.
Run Code Online (Sandbox Code Playgroud)

为了实现,make_integer_sequence我们需要一个辅助结构make_helper.

template< class T , class N >
using make_integer_sequence = typename make_helper<T,N>::type;
Run Code Online (Sandbox Code Playgroud)

实施make_helper并不太难.

template< class T, T N, T... I >
struct make_helper
{
   typedef …
Run Code Online (Sandbox Code Playgroud)

c++ gcc c++11 c++14

47
推荐指数
3
解决办法
2万
查看次数

为什么在C++ 11或C++ 14中没有进驻迭代器?

C++ 98有front_inserter,back_inserterinserter,但在C++ 11或草案C++ 14中似乎没有任何这些版本.有没有我们不能有任何技术原因front_emplacer,back_emplaceremplacer

c++ iterator stl c++11 c++14

46
推荐指数
2
解决办法
4321
查看次数

为什么在C++ 14中运行时大小的数组和std :: dynarray?

草案C++ 14包括运行时大小的数组和std::dynarray容器.从我所知道的,两者之间的唯一真正的区别在于std::dynarray有一个STL接口(例如begin,end,size,等),同时运行时大小的数组没有.那么为什么C++ 14需要它们呢?

我知道运行时大小的数组是核心语言的std::dynarray一部分,同时也是标准库的一部分,但是该提议std::dynarray清楚地表明作者希望编译器在许多情况下能够提供特殊支持,std::dynarray以便它可以高效尽可能地,即,与运行时大小的数组一样高效.因此,语言/库的区别似乎有点人为.

那么,为什么C++ 14需要两个运行时大小的数组std::dynarray呢?并且鉴于它std::dynarray具有更丰富的(STLified)接口,为什么不只是删除运行时大小的数组,假设std::dynarray可以以相同的运行时效率实现?

澄清

当我谈到"运行时大小的数组"时,我指的是N3639中描述的新的C++ 14核心语言特性,而不是传统的C数组或VLA或C++ 11中的任何内容.

c++ dynamic-arrays dynarray c++14

45
推荐指数
1
解决办法
9734
查看次数

C++ 11和C++ 14中`bsearch`的规范是否有缺陷?

继我对这个问题的回答之后,在C++ 11和C++ 14中:

[C++11, C++14: 25.5/2]:内容与标准C库头相同<stdlib.h>,但以下情况除外:

[C++11, C++14: 25.5/3]: 功能签名:

bsearch(const void *, const void *, size_t, size_t,
        int (*)(const void *, const void *));
Run Code Online (Sandbox Code Playgroud)

被两个声明取代:

extern "C" void *bsearch(const void *key, const void *base,
                         size_t nmemb, size_t size,
                         int (*compar)(const void *, const void *));

extern "C++" void *bsearch(const void *key, const void *base,
                           size_t nmemb, size_t size,
                           int (*compar)(const void *, const void *));
Run Code Online (Sandbox Code Playgroud)

两者都具有与原始声明相同的行为.

然而,

[C++11, C++14: 7.5/5]:如果两个声明声明具有相同名称的函数,并且参数类型列表(8.3.5)是同一命名空间的成员,或者声明具有相同名称的对象是同一命名空间的成员,并且声明为这些名称提供不同的语言链接,该计划是不正常的; 如果声明出现在不同的翻译单元中,则无需诊断.[..]

这是一个缺陷吗?

c++ language-lawyer c++11 c++14 bsearch

45
推荐指数
1
解决办法
1739
查看次数

C++ 14中的递归lambda函数

在C++ 11中编写递归lambda函数有一个经常重复的"技巧",如下所示:

std::function<int(int)> factorial;
factorial = [&factorial](int n)
{ return n < 2 ? 1 : n * factorial(n - 1); };

assert( factorial(5) == 120 );
Run Code Online (Sandbox Code Playgroud)

(例如,C++ 0x中的递归lambda函数.)

这种技术有两个直接的缺点:std::function<Sig>对象的目标(通过引用捕获)与非常特定的std::function<Sig>对象(此处factorial)相关联.这意味着通常无法从函数返回生成的仿函数,否则引用将保持悬空状态.

另一个(尽管不那么直接)问题是使用std::function通常会阻止编译器优化,这是在其实现中需要类型擦除的副作用.这不是假设,可以很容易地进行测试.

在假设的情况下,递归lambda表达式真的很方便,有没有办法解决这些问题?

c++ lambda c++14

44
推荐指数
2
解决办法
6646
查看次数

我应该将std :: string与“ string”或“ string” s比较吗?

考虑以下代码片段:

bool foo(const std::string& s) {
    return s == "hello"; // comparing against a const char* literal
}

bool bar(const std::string& s) {
    return s == "hello"s; // comparing against a std::string literal
}
Run Code Online (Sandbox Code Playgroud)

乍一看,它看起来像比对并const char*需要更少的组装说明1,作为使用字符串字面量会导致就地建设std::string

编辑:正如答案中指出的那样,我忘记了有效地s.compare(const char*)将被调用的事实foo(),因此在这种情况下当然不会进行就地构建。因此,请在下面删除一些行。

但是,请operator==(const char*, const std::string&)参阅参考资料:

所有比较都是通过compare()成员函数完成的。

根据我的理解,这意味着我们将需要构造一个结构std::string来执行比较,因此我怀疑最终的开销将是相同的(尽管对的调用已将其隐藏了operator==)。

  • 我应该选择哪个比较?
  • 一个版本是否比另一个版本具有优势(可能在特定情况下)?

1我知道更少的汇编指令并不一定意味着更快的代码,但是我不想在这里进行微基准测试。

c++ string-comparison string-literals c++14 c++17

44
推荐指数
3
解决办法
2894
查看次数

std :: swap vs std :: exchange vs swap operator

的实现std::swap可能是这样的:

template <class T> void swap (T& a, T& b)
{
  T c(std::move(a)); a=std::move(b); b=std::move(c);
}
template <class T, size_t N> void swap (T (&a)[N], T (&b)[N])
{
  for (size_t i = 0; i<N; ++i) swap (a[i],b[i]);
}
Run Code Online (Sandbox Code Playgroud)

实现std::exchangen3668可能如下所示:

 template< typename T, typename U = T >
   T exchange( T & obj, U && new_val )
   {
     T old_val = std::move(obj);
     obj = std::forward<U>(new_val);
     return old_val;
   }
Run Code Online (Sandbox Code Playgroud)

它说:

对于原始类型,这相当于明显的实现,而对于更复杂的类型,这个定义

  • 当该类型定义移动构造函数时,避免复制旧值
  • 接受任何类型作为新值,利用任何转换赋值运算符
  • 如果它是临时的或移动的,则避免复制新值.

我选择了与atomic_exchange对称的名称,因为它们的行为相同,除了这个函数不是原子的.

n3746还提出了一个内置的交换运算符,如下所示: …

c++ swap c++14

43
推荐指数
2
解决办法
9115
查看次数