I try to create a locale with following line of code:
std::locale loc(std::locale::classic(), new comma);
The definition of comma is:
struct comma : std::numpunct<char> {
char do_decimal_point() const { return ','; }
};
I thought it should work as I saw a similar constructor call in the MSDN documentation to facet. Unfortunatelly I get the error:
error C2664: '__thiscall std::locale::std::locale(const char *,int)' : cannot convert parameter number 1 from 'const class std::locale' in 'const char *'
Do you know, how I can get it right?
There are a some answers on Stackoverflow, which do it right this way (this, or this one). But it seems, that the old VC6 compiler doesn't support this constructor (although the example in the VC6 documentation uses it). But there must be a way to use facets with VC6, otherwise it wouldn't be part of the documentation.
To create a std::locale with a user defined facet we can use _ADDFAC. In the documentation to the locale constructor I found this helpful hint:
[...] you should write _ADDFAC(loc, Facet) to return a new locale that adds the facet Facet to the locale loc, since not all translators currently support the additional template constructors
VC6 doesn't seem to support the additional template constructors.
Sample Code:
std::istringstream iss("333,444"); // comma is decimal mark
std::locale loc(std::_ADDFAC(iss.getloc(), new comma));
iss.imbue(loc);
iss >> e;
std::cout << e << std::endl; // prints 333.444
Related
I'm trying to reproduce (*) something similar to Python fstring, or at least its format function (and while at it, I'd like to implement something like its "Mini-language").
(*) N.B.: please note that I am aware of the existence of the standard lib's format library, as well as the existence of the {fmt} library; but,
a: neither the g++ (11.2.1) nor the clang++ (12.0.1) that I have on my machine can compile code including <format>, and
b: I don't want to use the excellent {fmt} lib, because I'm precisely trying to do my own thing/thingy.
I'm going to use a string in input to my format object, and any number of additional arguments, like that:
// First, some vars
std::string stef{"Stéphane"};
std::string cpp{"C++"};
int ilu3t{3000};
// Then the big deal
std::string my_fstring = badabwe::format(
"My name is {stef}, and I love {cpp} {ilu3t} !",
cpp,
stef,
ilu3t
);
// Obviously, only the 1st parameter is positional!
// my_fstring should now be:
// My name is Stephane, and I love C++ 3000 !
That's one of the first problem, I have to solve. I think this process is called reflection (please let me know if it's the case).
Next I need to handle a variable number of arguments; the 1st parameter is the only positional and mandatory one (I'm still trying to find a way to iterate over a parameter pack), but its a subject for another question.
A function is not aware of name of parameters passed it. The parameter doen't even have to have a name:
void foo(int x); // name of the argument is x
foo(42); // 42 has no name
As suggested in a comment, if you want some mapping between strings (values to be replaced) and strings (their names) then you can use a map. To avoid the caller to spell out this mapping you can use a macro (usually to be avoided, but for now its the only way to get the name of a variable as a string):
#include <iostream>
#include <string>
#include <unordered_map>
using token_t = std::unordered_map<std::string,std::string>;
std::string format(const std::string& tokenized,const token_t& token) {
return "test";
}
#define tokenize(token) { #token , to_string(token) }
using std::to_string;
std::string to_string(const std::string& str) { return str; }
int main() {
std::string stef{"Stéphane"};
std::string cpp{"C++"};
int ilu3t{3000};
std::string my_fstring = format(
"My name is {stef}, and I love {cpp} {ilu3t} !",
{
tokenize(cpp),
tokenize(stef),
tokenize(ilu3t)
}
);
}
I assumed that you can use std::to_string, though there is no std::to_string(const std::string&) hence I added a custom implementation.
I am using Il2CppInspector to generate scaffolding for a Unity game. I am able to convert System.String (app::String in Il2CppInspector) to std::string using the functions provided below.
How would I reverse this process; how do I convert a std::string to System.String?
helpers.cpp
// Helper function to convert Il2CppString to std::string
std::string il2cppi_to_string(Il2CppString* str) {
std::u16string u16(reinterpret_cast<const char16_t*>(str->chars));
return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.to_bytes(u16);
}
// Helper function to convert System.String to std::string
std::string il2cppi_to_string(app::String* str) {
return il2cppi_to_string(reinterpret_cast<Il2CppString*>(str));
}
In short, I am looking for a function that takes in a std::string and returns an app::String
// Helper function to convert std::string to System.String
app::String string_to_il2cppi(std::string str) {
// Conversion code here
}
The accepted answer is actually wrong, there is no size parameter and copying stops at the first null byte (0x00) according to the MSDN documentation.
The following code fixes these problems and works correctly:
app::String* string_to_il2cppi(const std::string& string)
{
const auto encoding = (*app::Encoding__TypeInfo)->static_fields->utf8Encoding;
const auto managed_string = app::String_CreateStringFromEncoding((uint8_t*)&string.at(0), string.size(), encoding, nullptr);
return managed_string;
}
A quote from djkaty:
To create a string, you cannot use System.String‘s constructors –
these are redirected to icalls that throw exceptions. Instead, you
should use the internal Mono function String.CreateString. This
function has many overloads accepting various types of pointer and
array; an easy one to use accepts a uint16_t* to a Unicode string and
can be called as follows [...]
Export Il2CppInspector with all namespaces, which will give you access to Marshal_PtrToStringAnsi.
app::String* string_to_il2cppi(std::string str) {
return app::Marshal_PtrToStringAnsi((void*)&str, NULL);
}
Limitation: do not attempt to convert a string with null terminators inside of them example:
std::string test = "Hello\0world";
Use BullyWiiPlaza's solution if this is an issue for you.
I can't use non-primitive types as keys for associative arrays; attempting to do so will result in the following error on the line where I define the AA:
Error: AA key type MyString does not have 'bool opEquals(ref const MyString) const
I first discovered this when using the type CollisionHandler[Tuple!(TypeInfo, TypeInfo)] where CollisionHandler is an alias for a function pointer type.
However, even the example code from the "Using Structs or Unions as the KeyType" heading under the Associative array documentation page fails with the same error:
import std.string;
struct MyString
{
string str;
size_t toHash() const #safe pure nothrow
{
size_t hash;
foreach (char c; str)
hash = (hash * 9) + c;
return hash;
}
// opEquals defined here?
bool opEquals(ref const MyString s) const #safe pure nothrow
{
return std.string.cmp(this.str, s.str) == 0;
}
}
int[MyString] foo; // errors here
void main() {
}
Here, MyString.opEquals is defined and should have the proper signature, yet the dmd compiler says that it isn't implemented. The fact that this snippet comes straight from the docs makes me suspect it's a compiler bug, but maybe I'm just missing something?
Running DMD under Linux, but the issue also happens under Windows 7. DMD version:
$ dmd --help
DMD64 D Compiler v2.066.1
Copyright (c) 1999-2014 by Digital Mars written by Walter Bright
Documentation: http://dlang.org/
...
This is a case of a misleading error message emitted by the compiler.
The problem is with the #safe annotation on the opEquals method. In 2.066.1, std.string.cmp is not #safe - however, the compiler displays the wrong error message. If you rename opEquals to something else, e.g. foo, you'll get a different error message:
test.d(19): Error: safe function 'test.MyString.foo' cannot call system function
'std.algorithm.cmp!("a < b", string, string).cmp'
The workaround is to remove #safe, or replace it with #trusted.
Note that this problem does not manifest in the development version of DMD, so it should be fixed in 2.067.0.
I have a class constructor like so:
DotDashLogMatcher( std::stringstream const& pattern );
I call it like so:
std::stringstream s;
DotDashLogMatcher( s << "test" );
This is an over-simplified example, but that is essentially what is going on. Here is the exact compiler error I'm getting. Note that for some reason the resulting object that is passed in is a basic_ostream, I am not sure if this is normal. It isn't able to cast it to an std::stringstream like my function expects.
error C2664: 'DotDashLogMatcher::DotDashLogMatcher(const stlpd_std::stringstream &)' : cannot convert parameter 1 from 'stlpd_std::basic_ostream<_CharT,_Traits>' to 'const stlpd_std::stringstream &'
with
[
_CharT=char,
_Traits=stlpd_std::char_traits<char>
]
Reason: cannot convert from 'stlpd_std::basic_ostream<_CharT,_Traits>' to 'const stlpd_std::stringstream'
with
[
_CharT=char,
_Traits=stlpd_std::char_traits<char>
]
No constructor could take the source type, or constructor overload resolution was ambiguous
I'm using VS2003 and STLport on Windows.
Anyone know where I'm going wrong here? Why won't this code compile? I apologize in advance if I am lacking information. I will update my question for those that request more info.
operator<< does not return a std::stringstream because it is inherited from std::ostream. See:
http://www.cplusplus.com/reference/iostream/stringstream/
You may use:
DotDashLogMatcher( s );
Or you may change your method declaration in order to match the return type.
I believe you should split the statement into two separate commands:
s << "test";
DotDashLogMatcher( s );
as the parameter is passed by reference and thus needs to be modifiable, therefore an l-value.
Maybe you want to change:
DotDashLogMatcher( std::stringstream const& pattern );
Into:
DotDashLogMatcher( std::ostream const& pattern );
The problem is that operator << is overloaded for std::ostream and returns a std::ostream.
If you can;t change it there are several workarounds.
std::stringstream s;
s << "test"
DotDashLogMatcher( s );
// slightly more dangerious but should work.
std::stringstream s;
DotDashLogMatcher( static_cast<std::stringstream const&>(s << "test") );
The following code fragment gives the compilation error
call of overloaded ‘QString(int)’ is ambiguous with qt 4.7.3
(system is linux 64bit, debian unstable)
struct QSAConnection
{
QSAConnection() : sender(0), signal(0), function_ref() { }
QSAConnection(QObject *send, const char *sig, QSObject ref)
: sender(send), signal(QLatin1String(sig)), function_ref(ref) { }
QObject *sender;
QString signal;
QSObject function_ref;
};
Any tips?
The relevant bit is this line:
QSAConnection() : sender(0), signal(0), function_ref() { }
Since signal is a QString, the signal(0) bit is trying to call a constructor on the QString class that takes an integer as its only parameter. QString has no such constructor according to the Qt documentation. It does however have a constructor taking a char, and a QChar which has an implicit conversion from int. I expect it's ambiguous between those two.
Did you mean this instead?
QSAConnection() : sender(0), signal(), function_ref() { }
Which will default initialize signal. Note that technically it's not necessary to include it in the initializer list at all in that case.
It's a good thing. If it was not ambiguous, you might hit a null-pointer exception on QString::QString(char const* src). This is a common mistake with std::string.