std::filesystem example not compiling on c++ 17 - c++

I cant compile this official cpp filesystem reference example using c++ 17 clang:
https://en.cppreference.com/w/cpp/filesystem/recursive_directory_iterator
#include <fstream>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
fs::current_path(fs::temp_directory_path());
fs::create_directories("sandbox/a/b");
std::ofstream("sandbox/file1.txt");
fs::create_symlink("a", "sandbox/syma");
// Iterate over the `std::filesystem::directory_entry` elements explicitly
for (const fs::directory_entry& dir_entry :
fs::recursive_directory_iterator("sandbox"))
{
std::cout << dir_entry << '\n';
}
std::cout << "-----------------------------\n";
// Iterate over the `std::filesystem::directory_entry` elements using `auto`
for (auto const& dir_entry : fs::recursive_directory_iterator("sandbox"))
{
std::cout << dir_entry << '\n';
}
fs::remove_all("sandbox");
}
The compiler is returning:
/main.cpp:17:19: error: invalid operands to binary expression ('std::__1::ostream' (aka 'basic_ostream') and
'const fs::directory_entry')
std::cout << dir_entry << std::endl;
Can anyone help?

There was a defect in C++17 standard that didn't allow operator<< to be called with std::filesystem::directory_entry, reported in LWG 3171. It's now fixed as defect report, but it seems clang only fixed it in version 14: https://godbolt.org/z/3arTcGYvY. gcc seems to have backported the fix to all versions that support std::filesystem (that is, gcc9.1 and up): https://godbolt.org/z/fh7cdMxso

Related

std::ranges::remove still not suported / broken on clang trunk when using libstdc++?

Works fine on gcc trunk, but not on clang trunk, both with libstd++.
Or am I missing something exceedingly obvious?
Godbolt
#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>
std::ostream& operator<<(std::ostream& os, const std::vector<int>& v) {
for (auto&& e: v) os << e << " ";
return os;
}
int main() {
auto ints = std::vector<int>{1,2,3,4,5};
std::cout << ints << "\n";
auto [first, last] = std::ranges::remove(ints, 3);
ints.erase(first, last);
std::cout << ints << "\n";
}
gcc is clean. clang gives a WALL OF ERRORS, complaining about missing "__begin".
UPDATE: If I use -stdlib=libc++ then clang says "never heard of it", so I guess they are just not there yet.
new Godbolt
This seems to be a Clang bug, affecting ranges when using libstdc++, see this issue with the underlying cause which is still open and other issues linked to it as duplicates with examples how it affects ranges with libstdc++. There seems to have been some work on it about two weeks ago.
In libc++ std::ranges::remove does not seem to be implemented yet as you noticed and as stated on its status page for ranges implementation.

Searching for files with specific extension - using recursive_directory_iterator - <filesystem> library

I am trying to search for files with certain extensions in a directory, using the "recursive_directory_iterator" function inside library.
I am using Visual Studio Express 2017.
I am following the code in this answer:
https://stackoverflow.com/a/47975458/4145697
Here is my code:
#include <windows.h>
#include <iostream>
#include <filesystem>
#include <string>
void get_list_of_files(void)
{
std::string constructed_path_str_dbg = "C:\\Cpp_trials\\Trials\\Debug\\baseline\\cpp_files_trial";
std::string ext(".sample");
for (auto& p : fs::recursive_directory_iterator(constructed_path_str_after))
{
if (p.path().extension() == ext()) // errors E0980 and C2064
std::cout << p << '\n'; // errors E0349 and C2679
}
}
But I am having the following compilation errors:
E0980 call of an object of a class type without appropriate operator() or conversion functions to pointer-to-function type
E0349 no operator "<<" matches these operands
C2064 term does not evaluate to a function taking 0 arguments
C2679 binary '<<': no operator found which takes a right-hand operand of type 'const std::filesystem::directory_entry' (or there is no acceptable conversion)
According to the code you provided, I tested and modified it.
Change constructed_path_str_after to constructed_path_str_dbg
Change ext() to ext
The following are my test results:
#include <fstream>
#include <iostream>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
int main()
{
std::string constructed_path_str_dbg = "C:\\Cpp_trials\\Trials\\Debug\\baseline\\cpp_files_trial";
std::string ext(".txt");
for (auto& p : fs::recursive_directory_iterator(constructed_path_str_dbg))
{
if (p.path().extension() == ext)
std::cout << p << '\n';
}
return 0;
}
I hope to know why you would use constructed_path_str_after, because this is related to your problem solving. I can only speculate on your needs based on the existing code.

Misinterpretation of operator precedence when using ostream and ostringstream

The following code has different compile results. From the error message I'm receiving it seems there's a confusion about operators precedence () and <<. I can easily overcome this issue by using a function. However I would like to understand and to know:
a) Which compiler it's evaluating correctly the expression? MSVC2017 seems more logical to me.
b) Is there an workaround still using MACROs?
Full sample code I used.
#include <cstdlib>
#include <typeinfo>
#include <sstream>
#include <iostream>
#ifndef NDEBUG
#define EXPR_INSPECT(param_)\
( (std::ostringstream{} << "< " #param_ " [" << typeid(param_).name() << "] > : " << param_).str() )
#else
#define EXPR_INSPECT(param_)\
(param_)
#endif //NDEBUG
int main(int argc, char *argv[])
{
auto ull_x {99LLU};
std::string string_x {"Checking..."};
std::cout << EXPR_INSPECT( ull_x) << std::endl;
std::cout << EXPR_INSPECT(string_x) << std::endl;
return EXIT_SUCCESS;
}
MSVC2017 works perfectly!
G++ 8.2.0 (MSYS2/MINGW) issues the following error: 'std::basic_ostream::__ostream_type' {aka 'class std::basic_ostream'} has no member named 'str' Attempts to call str() on ostream instead of ostringstream.
EDIT:
The problem here can also be reproduced by clang using Wandbox. Here is a minimal example:
#include <sstream>
#include <iostream>
int main()
{
auto s = std::ostringstream{};
decltype(((std::ostringstream{}) << "< "))::nothing;
decltype((s << "< "))::nothing;
}
In wandbox, clang found the second type std::basic_ostream, while the first type std::basic_ostringstream. That's very strange.

lowest() is not a member of std::numeric_limits

I am trying to compile the following code:
#include <iostream>
#include <limits>
int main()
{
std::cout << std::numeric_limits<int>::lowest() << std::endl;
}
and I get the following error:
../main.cpp:5: error: 'lowest' is not a member of 'std::numeric_limits<int>'
cout << std::numeric_limits<int>::lowest() << std::endl;
^
I am using QT Creator 3.1.1 on Ubuntu 15.04, the compiler is set to GCC by default (/usr/bin/g++).
Anyone have an idea what could be the problem?
The lowest function was introduced in the C++11 standard, so you need to enable C++11 compatibility with the -std=c++11 flag (it's not enabled by default).

Avoiding compiler issues with abs()

When using the double variant of the std::abs() function without the std with g++ 4.6.1, no warning or error is given.
#include <algorithm>
#include <cmath>
double foobar(double a)
{
return abs(a);
}
This version of g++ seems to be pulling in the double variant of abs() into the global namespace through one of the includes from algorithm. This looks like it is now allowed by the standard (see this question), but not required.
If I compile the above code using a compiler that does not pull the double variant of abs() into the global namespace (such as g++ 4.2), then the following error is reported:
warning: passing 'double' for argument 1 to 'int abs(int)'
How can I force g++ 4.6.1, and other compilers that pull functions into the global namespace, to give a warning so that I can prevent errors when used with other compilers?
The function you are using is actually the integer version of abs, and GCC does an implicit conversion to integer.
This can be verified by a simple test program:
#include <iostream>
#include <cmath>
int main()
{
double a = -5.4321;
    double b = std::abs(a);
double c = abs(a);
std::cout << "a = " << a << ", b = " << b << ", c = " << c << '\n';
}
Output is:
a = -5.4321, b = 5.4321, c = 5
To get a warning about this, use the -Wconversion flag to g++. Actually, the GCC documentation for that option explicitly mentions calling abs when the argument is a double. All warning options can be found here.
Be warned, you don't need to explicitly #include <cmath>, <iostream> does the damage as well (and maybe some other headers). Also, note that -Wall doesn't give you any warnings about it.
#include <iostream>
int main() {
std::cout << abs(.5) << std::endl;
std::cout << typeid(decltype(abs)).name() << std::endl;
}
Gives output
0
FiiE
On
gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04)