У меня есть проект, в котором я печатаю std::filesystem::directory_entry
из directory_iterator. С другой стороны, у меня есть полностью независимый класс с перегрузкой 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
, компиляция проходит (это своего рода обходной путь, но не предполагалось, что operator<<
имеет доступ к приватному классу). Однако не получится, если я просто расстанусь и не подружусь.
основной.cpp:
#include "var.hpp"
#include <iostream>
#include <filesystem>
int main() {
std::cout << std::filesystem::directory_entry() << "\n";
std::cout << Var(1l) << "\n";
return 0;
}
переменная.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
переменная.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 с аналогичным результатом).
<source>:11:18: error: no matching constructor for initialization of 'VarType' (aka 'variant<long, basic_string<char> >') Var(T value) : _value{value} { ^ ~~~~~~~
- person Mansoor   schedule 29.08.2020Var
с помощьюdirectory_entry
. Если это исправлено в багажнике, следует ли считать это известной ошибкой компилятора? Спасибо за ссылку на богбол. - person Askold Ilvento   schedule 29.08.2020directory_entry
не имеет явногоostream& operator<<
, и поэтому диалог должен использоваться в любом случае. Компилятор выбирает мой, то есть болеет и SFINAE не помогает. Эксплицит решает эту проблему. Версия компилятора Trunk имеет оператор ostream&‹‹ для directory_entry, компилятор не ищет преобразования, не так ли? Это объясняет большинство вопросов. Почему друг делает обходной путь? - person Askold Ilvento   schedule 29.08.2020