gpt4 book ai didi

c++ - directory_entry 的输出与具有变体的类的重载 ostream 运算符<< 冲突

转载 作者:行者123 更新时间:2023-12-02 10:27:36 25 4
gpt4 key购买 nike

我有一个项目,我打印 std::filesystem::directory_entry从目录迭代器。另一方面,我有一个完全独立的重载类 std::ostream& operator<< ,它有一个模板化的构造函数,它初始化一个 std::variant成员。

#include <variant>
#include <iostream>
#include <filesystem>

typedef std::variant<long, std::string> VarType;

class Var {
VarType _value;
public:
template<typename T>
Var(T value) : _value{value} {
}
};

std::ostream& operator<< (std::ostream& stream, const Var&) {
return stream;
}

int main() {
std::cout << std::filesystem::directory_entry() << "\n";//tigger compling error
return 0;
}
编译失败:
main.cpp: In instantiation of ‘Var::Var(T) [with T =
std::filesystem::__cxx11::directory_entry]’: main.cpp:25:49:
required from here main.cpp:11:30: error: no matching function for
call to ‘std::variant<long int, double,
std::__cxx11::basic_string<char, std::char_traits<char>,
std::allocator<char> > >::variant(<brace-enclosed initializer list>)’
Var(T value) : _value{value} {
... several pages of output ...
它似乎试图包装 directory_entry进入 Var , 在发送到 cout 之前,但我不确定。
您能否解释一下实际发生了什么以及为什么代码是错误的?
我四处测试。对于这个问题,无论我在 variant中输入什么似乎都可以。 ,即使是单个变体也生病了。这个
#include <variant>
#include <iostream>
#include <filesystem>

typedef std::variant<long, std::string> VarType;

class Var {
VarType _value;
public:
template<typename T>
Var(T value) : _value{value} {
}
};

std::ostream& operator<< (std::ostream& stream, const VarType&) {
return stream;
}

int main() {
std::cout << std::filesystem::directory_entry() << "\n";
return 0;
}
工作正常。如果我搬家 _value初始化到 c-tor 主体编译失败,出现相同的逻辑错误,但 operator= ,至少是一致的。显然它适用于非模板化的 c-tor。
如果我移动 ostream& operator<< 的实现到一个单独的单元并将其定义为 Var 的 friend ,编译通过(这是一种合适的解决方法,但不应该 operator<< 可以访问类的私有(private))。但是,如果我只是分开而不交 friend ,它就失败了。
主.cpp:
#include "var.hpp"
#include <iostream>
#include <filesystem>

int main() {
std::cout << std::filesystem::directory_entry() << "\n";
std::cout << Var(1l) << "\n";
return 0;
}
var.hpp:
#include <variant>
#include <ostream>

typedef std::variant<long, std::string> VarType;

class Var {
VarType _value;
public:
template<typename T>
Var(T value) : _value{value} {
}
friend std::ostream& operator<< (std::ostream& stream, const Var&); //works
};
//std::ostream& operator<< (std::ostream& stream, const Var&); //instead above does not works
var.cpp:
#include "var.hpp"

std::ostream& operator<< (std::ostream& stream, const Var&) {
return stream;
}
这让我完全迷失了。假设它试图调用 Var c-tor 上 <<这里应该没有区别。
为什么这样的改变很重要?
我用 g++8.4 构建( g++ -std=c++17 main.cpp var.cpp -lstdc++fs ,我也尝试了 clang7.0 并获得了类似的结果)。

最佳答案

有了曼苏尔的提示,我想我发现了。
联系人
这段代码很危险。

class Var {
public:
template<typename T>
Var(T value) {
}
};
避免这种情况。
编译器将尝试在 Var 的任何隐式转换中替换此类 c-tor。是可见的并且可能是合适的。
将 c-tor 标记为 explicit是限制这种野生替代的最直接方法。 SFINAE 和 enable_if可以通过其他方式来限制替换。
在我的情况下,错误的替代正是打破复杂性的原因,因为旧的符合 directory_entry没有 ostream<< 的直接定义.编译器查找转换器并找到合适的 Var .可以实例化但不能遵守。后者很好,因为如果可以的话,错误是无法追踪的。
有一个补丁 https://gcc.gnu.org/legacy-ml/gcc-patches/2018-06/msg01084.html大约在 2018 年(或者可能很快就解决了),它引入了明确的 ostream << directory_entry .
在那之前 directory_entry可以转换为 path像这样的隐式 c-tor
template<typename _Source,
typename _Require = _Path<_Source>>
path(_Source const& __source, format = auto_format)
这就是为什么 ostream << directory_entry如果没有 ostream<< 则有效是明确定义的。
friend
friend 实际上范围转换器可见性。这也有效
class Var {
VarType _value;
public:
template<typename T>
Var(T value) : _value{value} {
}
friend std::ostream& operator<< (std::ostream& stream, const Var&) {
return stream;
}
};
但是如果 std::ostream&被声明为友元并且定义(或其他声明)对 ostream << directory_entry 可见当它因为其他声明而再次破坏复杂性时,对于野生替换是可见的。这就解释了为什么分成几个单元并使用 friend 创建了一种解决方法。
SFINAE
SFINAE 不检查函数体。它仅适用于声明。 _value{value}是 body 。调用 SFINAE c-tor 应该像
  template< class T, typename = std::enable_if_t<std::disjunction_v<std::is_same<T, long>,  std::is_same<T, std::string>>>>
Var(T value) : _value{value} {
}
绝妙的想法如何处理 std::variant可以在这里挖出依赖的 c-tor:
How do I check if an std::variant can hold a certain type .

关于c++ - directory_entry 的输出与具有变体的类的重载 ostream 运算符<< 冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63641440/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com