8

我有一个具有复制构造函数和构造函数的类std::reference_wrapper

#include <functional>
#include <iostream>

class Class {
public:
    Class() {
        std::cout << "Class()" << std::endl;
    }
    Class(Class const &) {
        std::cout << "Class(Class const &)" << std::endl;
    }
    Class(std::reference_wrapper<Class>) {
        std::cout << "Class(std::reference_wrapper<Class>)" << std::endl;
    }
    Class(std::reference_wrapper<const Class>) {
        std::cout << "Class(std::reference_wrapper<const Class>)" << std::endl;
    }
};

int main() {
    Class a;
    Class b = a;
    Class c = std::ref(a);
    Class d = std::cref(a);
}

正常编译时(g++ --std=c++17 test.cpp),它可以按要求工作,依次调用四个构造函数:

$ ./a.exe
Class()
Class(Class const &)
Class(std::reference_wrapper<Class>)
Class(std::reference_wrapper<const Class>)

-pedantic但是,使用(ie, )编译g++ --std=c++17 -pedantic test.cpp会导致以下错误(以及另一个等效的错误std::cref):

test.cpp:23:22: error: conversion from 'std::reference_wrapper<Class>' to 'Class' is ambiguous
  Class c = std::ref(a);
                      ^
note: candidate: std::reference_wrapper<_Tp>::operator _Tp&() const [with _Tp = Class]
note: candidate: Class::Class(std::reference_wrapper<Class>)

为什么会这样(即,我如何违反标准,在Conversion constructor vs. conversion operator: priority中回答),以及如何在不-pedantic符合标准的情况下获得结果?

$ g++ --version
g++.exe (Rev1, Built by MSYS2 project) 7.2.0
4

2 回答 2

1

将构造函数定义为explicit避免与类operator T& () const中定义的转换运算符冲突std::reference_wrapper

#include <functional>
#include <iostream>

class Class {
public:
    Class() {
        std::cout << "Class()" << std::endl;
    }
    Class(Class const &) {
        std::cout << "Class(Class const &)" << std::endl;
    }
    explicit Class(std::reference_wrapper<Class>) {
        std::cout << "Class(std::reference_wrapper<Class>)" << std::endl;
    }
    explicit Class(std::reference_wrapper<const Class>) {
        std::cout << "Class(std::reference_wrapper<const Class>)" << std::endl;
    }

};

int main() {
    Class a;
    Class b = a;
    Class c = std::ref(a);  // call Class(Class const &) trough the conversion operator
    Class d(std::ref(a));   // call Class(std::reference_wrapper<Class>)
    Class e = std::cref(a); // call Class(Class const &) trough the conversion operator
    Class f(std::cref(a));  // call Class(std::reference_wrapper<const Class>)
}

或者删除构造函数重载 3 和 4 以始终使用复制构造函数Class(Class const &)

如果没有 pedantic 选项,您不会得到任何错误,因为 GCC 优先于复制构造函数而不是转换运算符,但这不是标准的一部分,没有定义优先级,因此会发生冲突。

于 2018-05-02T16:46:52.970 回答
1

我如何以符合标准的方式在没有 -pedantic 的情况下获得结果?

在您的情况下,创建具有完全匹配的重载:

Class(std::reference_wrapper<Class>&&) {
    std::cout << "Class(std::reference_wrapper<Class>)" << std::endl;
}
Class(std::reference_wrapper<const Class>&&) {
    std::cout << "Class(std::reference_wrapper<const Class>)" << std::endl;
}

演示

于 2018-05-02T16:32:40.733 回答