I'm trying to convert const std::filesystem::directory_entry (dirent) to tchar but I don't understand how it an be done. I tried a lot of ways. Can you help me?
Edited:
#include "pch.h"
#include <memory>
#include <filesystem>
#include <algorithm>
#include <iostream>
#include <tchar.h>
#include <string.h>
typedef wchar_t WCHAR;
namespace fs = std::filesystem;
int main() try
{
std::for_each(fs::recursive_directory_iterator("./foo/"), {},
[](fs::directory_entry const& dirent)
{
if (fs::is_regular_file(dirent) &&
dirent.path().filename() == "black.txt")
{
std::wstring = path.wstring();
}
});
}
catch (fs::filesystem_error const& e)
{
std::cerr << "error: " << e.what() << '\n';
}
You can convert std::filesystem::path to any form using these functions:
std::string string() const;
std::wstring wstring() const;
std::u16string u16string() const;
std::u32string u32string() const;
TCHAR is somewhat of a relic as mentioned in the comments, and you're much better off using any of the above alternatives.
If you're going to pass it to Win32 API functions, I would either suggest using wstring explicitly and not bother with the shape-shifting TCHAR at all.
What your code should look like is this:
if (fs::is_regular_file(dirent) &&
dirent.path().filename() == "black.txt")
{
std::wstring path_as_string = path.wstring();
}
No TCHAR, no C-style arrays no C-style memory copying.
Related
I'm using Redis with C++, so I'm using redis-cpp library to use it with this language. I'm trying to understand RESP protocol. As far as I know, this protocol can serialize and deserialize simple strings, errors, integers, bulk strings and arrays. I want to serialize and deserialize hash too, so I was trying to implement the code but is not as easy as I tough. This library implments some examples, so I was just trying to modify one of these examples:
Here is where data is called:
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <redis-cpp/execute.h>
namespace resps = rediscpp::resp::serialization;
namespace respds = rediscpp::resp::deserialization;
auto make_sample_data()
{
std::ostringstream stream;
put(stream, resps::array{
resps::simple_string{"This is a simple string."},
resps::error_message{"This is an error message."},
resps::bulk_string{"This is a bulk string."},
resps::integer{100500},
resps::array{
resps::simple_string("This is a simple string in a nested array."),
resps::bulk_string("This is a bulk string in a nested array.")
}
});
return stream.str();
}
I want to add a line similar to the others like: resps::hash(-add here an string, an integer, etc-)
And main function looks like this:
{
try
{
auto const data = make_sample_data();
std::cout << "------------ Serialization ------------" << std::endl;
std::cout << data << std::endl;
std::cout << "------------ Deserialization ------------" << std::endl;
std::istringstream stream{data};
print_sample_data(stream, std::cout);
std::cout << std::endl;
}
catch (std::exception const &e)
{
std::cerr << "Error: " << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Serialization function of simple_string, for example, is build like this:
#ifndef REDISCPP_RESP_SERIALIZATION_H_
#define REDISCPP_RESP_SERIALIZATION_H_
// STD
#include <cstdint>
#include <forward_list>
#include <ostream>
#include <string_view>
#include <type_traits>
#include <tuple>
#include <utility>
// REDIS-CPP
#include <redis-cpp/detail/config.h>
#include <redis-cpp/resp/detail/marker.h>
#include <redis-cpp/resp/detail/overloaded.h>
namespace rediscpp
{
inline namespace resp
{
namespace serialization
{
template <typename T>
void put(std::ostream &stream, T &&value)
{
value.put(stream);
}
class simple_string final
{
public:
simple_string(std::string_view value) noexcept
: value_{std::move(value)}
{
}
void put(std::ostream &stream)
{
stream << detail::marker::simple_string
<< value_
<< detail::marker::cr
<< detail::marker::lf;
}
private:
std::string_view value_;
};
And deserialization for same function is build like this:
#ifndef REDISCPP_RESP_DESERIALIZATION_H_
#define REDISCPP_RESP_DESERIALIZATION_H_
// STD
#include <cstdint>
#include <istream>
#include <stdexcept>
#include <string>
#include <string_view>
#include <variant>
#include <vector>
// REDIS-CPP
#include <redis-cpp/detail/config.h>
#include <redis-cpp/resp/detail/marker.h>
namespace rediscpp
{
inline namespace resp
{
namespace deserialization
{
[[nodiscard]]
auto get_mark(std::istream &stream)
{
switch (stream.get())
{
case detail::marker::simple_string :
return detail::marker::simple_string;
case detail::marker::error_message :
return detail::marker::error_message;
case detail::marker::integer :
return detail::marker::integer;
case detail::marker::bulk_string :
return detail::marker::bulk_string;
case detail::marker::array :
return detail::marker::array;
default:
break;
}
throw std::invalid_argument{
"[rediscpp::resp::deserialization::get_mark] "
"Bad input format."
};
}
template <typename T>
[[nodiscard]]
T get(std::istream &stream)
{
return {stream};
}
class simple_string final
{
public:
simple_string(std::istream &stream)
{
std::getline(stream, value_);
value_.pop_back(); // removing '\r' from string
}
[[nodiscard]]
std::string_view get() const noexcept
{
return value_;
}
private:
std::string value_;
};
How can I add hash as a type and build the functions in serialize and deserialize as it was done with simple_string? Thanks in advance!!
I use MinGW 8.1.0 64-bit. This code snippet:
#include <clocale>
#if __has_include(<codecvt>)
#include <codecvt>
#endif
#include <cstdlib>
#include <locale>
#include <string>
#include <wchar.h>
#include <iostream>
int main() {
auto utf8_decode = [](const std::string &str) -> std::wstring {
std::wstring_convert<std::codecvt_utf8<wchar_t>> myconv;
return myconv.from_bytes(str);
};
std::string test = "=";
auto s = utf8_decode(test);
std::wcout << s << std::endl;
return 0;
}
outputs a hieroglyphic (or some gibberish) on Windows, but outputs = (as expected) on Linux.
Is this a bug in standard library or am I missing something?
Looks like this is indeed a bug in MinGW libstdc++.dll; codecvt incorrectly chooses big endian so = (0x3d) becomes 㴀 (0x3d00).
Proposed workaround - manually force little-endian by using codecvt_utf8<wchar_t, 0x10ffff, std::little_endian>
I'm completely new to the range library, so I shouldn't be surprised that this code isn't compiling and I cannot figure out why:
#include <iostream>
#include <algorithm>
#include <fstream>
#include <iterator>
#include <vector>
#include <range/v3/all.hpp>
#include <range/v3/view/all.hpp>
using namespace ranges::v3;
std::ifstream open_file(const std::string &filename) {
return std::ifstream{filename};
}
int count_lines(std::ifstream &in) {
return std::count(std::istreambuf_iterator<char>{in},
std::istreambuf_iterator<char>{}, '\n');
}
std::vector<int>
count_lines_in_files(const std::vector<std::string> &filenames) {
auto a1 = filenames | view::transform(open_file) | view::transform(count_lines);
return a1;
}
int main() {
const std::vector<std::string> files{"listing1_1.cpp",
"listing1_2.cpp",
"listing1_4.cpp",
"listing1_5.cpp"};
const auto result = count_lines_in_files(files);
std::cout << ranges::view::all(result) << '\n';
}
It appears that the complaint is about a1, which the compiler tells me "error: variable has incomplete type 'void'."
Can someone see what I'm doing wrong, or tell me how to properly chain these together if possible?
Thanks in advance!
As noted by Porsche9II, "std::ifstream doesn't have a copy constructor". You can find more on this topic here:
Why are iostreams not copyable?
C++11 introduced a move constructor (6) for std::basic_ifstream, so you could write
auto open_file(const std::string &filename) {
return std::ifstream{filename};
}
auto count_lines(std::ifstream &&in) {
return std::count(std::istreambuf_iterator<char>{in},
std::istreambuf_iterator<char>{}, '\n');
}
Testable HERE.
std::ifstream doesn't have a copy constructor - returning std::ifstream by a function is not a good idea. One possible solution: opening and counting should take place in one function.
I am trying to reverse a string (c++, compiling with g++).
Isn't string considered a container for the algorithm functions?
This is the code:
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string str = "hello";
str.reverse(str.begin(), str.rbegin());
return 0;
}
Thanks
The std::string class template does not have a member function called reverse. There is a std::reverse function located in the <algorithm> header. You probably want to use it in a following manner:
#include <string>
#include <algorithm>
int main() {
std::string str = "hello";
std::reverse(str.begin(), str.end());
}
Note the use of str.end() in place of your str.rbegin(). You can also define a new string and use the string constructor overload that accepts reverse iterators:
#include <string>
int main() {
std::string str = "hello";
std::string reversestr(str.rbegin(), str.rend());
}
std::string has no method reverse. But std::reverse exists:
#include <string>
#include <algorithm>
#include <iostream>
int main()
{
std::string str = "hello";
std::reverse(str.begin(), str.end());
std::cout << str << "\n"; // prints "olleh"
}
My problem seems to be very basic but I could not find a solution for it. I need to write a code which helps debugging by reporting the line and location of exception throwing. The problem is that __LINE__ is an int value and I have problem with its conversion into string in the following code where std::string(line) is used:
#pragma once
#include <stdexcept>
#include <cstring>
class CRuntime_error_line: public std::runtime_error
{
public:
CRuntime_error_line(const char * msg, const char * file,int line)
:runtime_error(std::string(msg)+" #"+":"+std::string(line)){}
};
#define runtime_error_line(msg) CRuntime_error_line(msg,__FILE__,__LINE__)
Seems std::string(line) cannot convert int to string and other solutions suggested online cannot be implemented inline and I don't know how to call a base constructor in second line!
compiler output:
log.h: In constructor ‘CRuntime_error_line::CRuntime_error_line(const
char*, const char*, int)’: log.h:10:124: error: invalid conversion
from ‘int’ to ‘const char*’ [-fpermissive] CRuntime_error_line(const
char * msg, const char * file,int
line):runtime_error(std::string(msg)+" #"+":"+std::string(line)){}
(Using g++ and linux environment)
edit:
the macro is supposed to be called this way:
throw runtime_error_line("Invalid somethihng ...!");
As is suggested by Borgleader std::to_string is your solution. It will also construct a temporary std::string for you, so there's no need to construct a temporary string from msg:
#pragma once
#include <stdexcept>
#include <cstring>
#include <string> // Add this to support std::to_string
class CRuntime_error_line: public std::runtime_error
{
public:
CRuntime_error_line(const char* msg, const char* file, int line)
: runtime_error(msg + " #:"s + std::to_string(line)){} // Use std::to_string here
};
#define runtime_error_line(msg) CRuntime_error_line(msg, __FILE__, __LINE__)
Without C++11 you can still do this it's just not as clean:
#pragma once
#include <stdexcept>
#include <cstring>
#include <sstream> // Use to include std::ostringstream
class CRuntime_error_line: public std::runtime_error
{
public:
CRuntime_error_line(const char* msg, const char* file, int line)
: runtime_error(static_cast<std::ostringstream&>(std::ostringstream() << msg << " #:" << line).str()){} // Use std::ostringstream here
};
#define runtime_error_line(msg) CRuntime_error_line(msg, __FILE__, __LINE__)
int this case may be better :
#define STRING_DEFINE1(x) #x
#define STRING_DEFINE(x) STRING_DEFINE1(x)
...
CRuntime_error_line(msg,__FILE__,STRING_DEFINE(__LINE__))
The simplest thing I can think of would be to write a to_string yourself:
#include <sstream>
std::string to_string(int i)
{
std::ostringstream os;
os << i;
return os.str();
}
Then call it as others have suggested.