小编for*_*818的帖子

为什么我不能将此运算符重载在与结构相同的命名空间中?

我有以下代码:

#include <iostream>
#include <vector>
namespace X {
    std::ostream& operator<<(std::ostream& os,const std::vector<double>& v){
        for (int i=0;i<v.size();i++){os << v[i] << " ";}
        return os;
    }
    namespace Y {
        struct A {std::vector<double> x;};    
        std::ostream& operator<<(std::ostream& os,const A& a){
            os << a.x << std::endl;
            return os;
        }
   }     
}

using namespace X;

int main(int argc, char** argv) {
   std::vector<double> v(10,0);
   std::cout << v << std::endl;
   Y::A a;
   std::cout << a << std::endl;
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

第一个重载是有效的,但第二个没有.由于某种原因,它找不到第一个.我收到错误:

no match for 'operator<<' (operand types are …
Run Code Online (Sandbox Code Playgroud)

c++ operator-overloading ostream

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

如何处理(深层)嵌套函数调用中的默认值?

假设有一个具有默认值的函数:

int foo(int x=42);
Run Code Online (Sandbox Code Playgroud)

如果这是由其他人这样调用:

int bar(int x=42) { return foo(x); }
int moo(int x=42) { return bar(x); }
Run Code Online (Sandbox Code Playgroud)

这当然只是一个人为的例子.但是,我有时情况非常相似.该参数仅从最高级别(moo)传递到最低级别,并且仅在实际使用时才传递.关于这一点的坏处是,当我更改foo为具有不同于42我必须搜索所有调用者的默认值并相应地更改默认值时.

是否有一些模式/成语可以避免这种情况?

我想到的唯一简单的解决方案是

int bar()      { return foo(); }
int bar(int x) { return foo(x); }
Run Code Online (Sandbox Code Playgroud)

但是,由于我有点懒,而且在实际代码中这会导致相当多的代码重复,我想避免这种情况.

c++ default-value

6
推荐指数
2
解决办法
164
查看次数

将函数指针传递给算法时选择正确的重载

问题

请耐心等待,这只是一个例子:

#include <algorithm>
#include <iterator>
struct foo {
    static int my_transform(int x) { return x;}
    static std::vector<int> my_transform(std::vector<int> x){
        std::vector<int> result;            
        std::transform(x.begin(),x.end(),std::back_inserter(result),my_transform);
        return result;
    }
};
Run Code Online (Sandbox Code Playgroud)

我期待发生什么

有两个可能的重载my_transform,但只有一个导致格式良好的模板实例化,而另一个模板实例化是不正确的.我希望丢弃不正确的一个以及上面的编译.

真正发生了什么

 main.cpp:165:75: error: no matching function for call to
 ‘transform(std::vector<int>::iterator, std::vector<int>::iterator, 
 std::back_insert_iterator<std::vector<int> >, <unresolved overloaded function type>)’
   std::transform(x.begin(),x.end(),std::back_inserter(result),my_transform);
                                                               ^
Run Code Online (Sandbox Code Playgroud)

如何解决它

将函数指针转换为正确的类型可以解决歧义并编译:

static std::vector<int> foo::my_transform(std::vector<int> x){
    std::vector<int> result;
    typedef int (*my_transform_t)(int);     
    std::transform(x.begin(),
                   x.end(),
                   std::back_inserter(result),
                   static_cast<my_transform_t>(my_transform));
    return result;
}
Run Code Online (Sandbox Code Playgroud)

问题

究竟是什么阻止了编译器选择"正确"的重载?考虑到只有一个可以导致有效的模板实例化,实际上并不存在歧义.

PS:请注意,这是C++ 98.在C++ 11及更高版本中,使用lambdas可以很容易地避免这个问题(感谢@appleapple指出这一点).

c++ templates function-pointers language-lawyer stl-algorithm

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

如何合并具有相同条件的两个函数?

我很快为这个问题编写了下面的课程.

我正在寻找一种方式来合并addFruit()removeFruit()减少的代码.

它们都使用相同的条件,但最后只是使用不同的函数调用.

我的代码:

#include <iostream>
#include <string>
#include <vector>

class MyClass
{
public:
    void addFruit(const std::string &str, int count)
    {
        if (str == "apples")
            addToVec(apples, count);
        else if (str == "oranges")
            addToVec(oranges, count);
        else if (str == "lemons")
            addToVec(lemons, count);
        else if (str == "melons")
            addToVec(melons, count);
        else if (str == "bananas")
            addToVec(bananas, count);
        else
            std::cout << "Unknown Fruit : " << str << '\n';
    }
    void removeFruit(const std::string &str)
    {
        if (str == "apples") …
Run Code Online (Sandbox Code Playgroud)

c++ design-patterns

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

trailing-return-type中占位符类型的用途是什么?

根据[dcl.fct]/2,下面的代码段是合法的.GCC和clang编译并执行代码,

#include <iostream>
int i = -1;
auto f()->auto&& { return i; }
int main(){
    f() = 2;
    std::cout << i << '\n';
}
Run Code Online (Sandbox Code Playgroud)

印花

2
Run Code Online (Sandbox Code Playgroud)

但是在C++中允许这个的目的是什么?

在上面的示例中,只需将trailing-return-type替换为,就可以获得相同的结果int&.换句话说,我正在寻找一个示例,其中包含占位符类型的trailing-return-type将是有意义的.

c++ language-lawyer

6
推荐指数
2
解决办法
215
查看次数

编译器生成的默认构造函数如何比只初始化成员什么都不做的自写结构更有效?

通过这个答案,我正在阅读核心准则

C.45:不要定义仅初始化数据成员的默认构造函数;改用类内成员初始化器

给出的理由是

原因

使用类内成员初始化器可使编译器为您生成函数。编译器生成的函数可以更有效。

请注意,这是专门针对默认构造函数的,该默认构造函数除了初始化成员外不执行任何操作,并且该准则建议不要编写这样的构造函数。

“坏”的例子是:

Example, bad

class X1 { // BAD: doesn't use member initializers
    string s;
    int i;
public:
    X1() :s{"default"}, i{1} { }
    // ...
};
Run Code Online (Sandbox Code Playgroud)

在该特定示例(或任何其他示例)中,编译器生成的构造函数比用户提供的构造函数更有效率吗?

我天真地希望初始化程序列表提供与类初始化程序相同的优化机会。

c++ initialization default-constructor cpp-core-guidelines

6
推荐指数
2
解决办法
96
查看次数

当方法不修改成员时,在const实例上调用非const方法是否为UB?

代码说出了上千个单词,所以...

这是使a发生突变的未定义行为const int

struct foo {
    int x;
    void modify() { x = 3; }
};

void test_foo(const foo& f) {
    const_cast<foo&>(f).modify();
}

int main(){
    const foo f{2};
    test_foo(f);
}
Run Code Online (Sandbox Code Playgroud)

那这个呢:

struct bar {
    void no_modify() { }
};

void test_bar(const bar& b) {
    const_cast<bar&>(b).no_modify();
}

int main(){
    const bar b;
    test_bar(b);
}
Run Code Online (Sandbox Code Playgroud)

const_cast当方法不改变对象时,是否可以通过const对象调用非const方法?

PS:我知道no_modify应该将其声明为const,然后这个问题毫无意义,但假设bars的定义不能更改。

PPS:只需确保:不要在家中(或其他任何地方)这样做。我绝不会让这样的代码通过审查。可以轻松避免强制转换。这是一个语言律师问题。

c++ const const-cast language-lawyer

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

C++ std::string 初始化性能更好(汇编)

我在玩 www.godbolt.org 来检查哪些代码会生成更好的汇编代码,但我不明白为什么这两种不同的方法会生成不同的结果(在汇编命令中)。

第一种方法是声明一个字符串,然后再设置一个值:

#include <string>
int foo() {
    std::string a;
    a = "abcdef";
    return a.size();
}
Run Code Online (Sandbox Code Playgroud)

其中,在我的 gcc 7.4 ( -O3) 输出中:

.LC0:
        .string "abcdef"
foo():
        push    rbp
        mov     r8d, 6
        mov     ecx, OFFSET FLAT:.LC0
        xor     edx, edx
        push    rbx
        xor     esi, esi
        sub     rsp, 40
        lea     rbx, [rsp+16]
        mov     rdi, rsp
        mov     BYTE PTR [rsp+16], 0
        mov     QWORD PTR [rsp], rbx
        mov     QWORD PTR [rsp+8], 0
        call    std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_replace(unsigned long, unsigned long, char const*, unsigned …
Run Code Online (Sandbox Code Playgroud)

c++ optimization

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

使用初始化列表声明动态分配数组的数组大小

我正在尝试使用初始化程序列表初始化动态声明的数组,但我注意到我必须使用 GCC 提供数组大小,否则会出现错误。如果忽略数组大小,使用 MSVC 尝试相同的操作不会导致任何错误。使用带有动态数组的初始值设定项列表时是否必须提供数组大小?这是实现定义的,这就是为什么两个编译器都不同的原因?

int *array { new int [3] {0, 1, 2} }; // Works with both MSVC and GCC.
int *array { new int [] {0, 1, 2} }; // Works only with MSVC, not GCC.
Run Code Online (Sandbox Code Playgroud)

c++ gcc dynamic-arrays visual-c++ language-lawyer

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

sfinae 检测容器:std:array 失败

我正在寻找一种使用 SFINAE 来实现某些功能的方法,该功能必须仅适用于某些容器:向量、列表、数组(设置在下面仅作为测试)

基于这个答案,我尝试了下面的代码,该代码使用了一个仅对所需容器返回 true 的特性类。

正如您在此处在线看到的,它失败了std::array

template <typename Container>
struct is_container : std::false_type { };

template <typename... Ts> struct is_container<std::array<Ts... >> : std::true_type { };
template <typename... Ts> struct is_container<std::vector<Ts...>> : std::true_type { };
template <typename... Ts> struct is_container<std::set<Ts...   >> : std::true_type { };
template <typename... Ts> struct is_container<std::list<Ts...  >> : std::true_type { };
template <typename... Ts> struct Dummy{};

int main()
{
    std::cout << "Dummy: " << is_container<Dummy<int>>::value << '\n';
    std::cout << "array: …
Run Code Online (Sandbox Code Playgroud)

c++ templates sfinae variadic-templates stdarray

6
推荐指数
2
解决办法
72
查看次数