As a C++ beginner I want to write some simple type casts. It there a way to create casting logic which can be used in the type new = (type)old format with the prefix parentheses?
string Text = "Hello";
char* Chars = "Goodbye";
int Integer = 42;
string Message = Text + (string)Integer + (string)Chars + "!";
I'd like to stick with this syntax if possible. For example the string cast of boost int Number = boost::lexical_cast<int>("Hello World") has an unattractive long syntax.
Just use a normal function that you overload for different types:
std::string str(int i) {
return "an integer";
}
std::string str(char* s) {
return std::string(s);
}
Then use if not like a cast, but as a normal function call:
string Message = Text + str(Integer) + str(Chars) + "!";
It's the most common thing in C++ to cast using a NAME<TYPE>(ARGUMENT) syntax, like in static_cast<int>(char). It makes sense to extend this the way boost does.
However, if you want to convert non-primitive types, you can use non-explicit constructors with a single argument and the cast operator.
class MyType {
public:
MyType(int); // cast from int
operator int() const; // cast to int
};
This is not possible if you are dealing with already existing types.
You cannot change the behaviour of the C-style cast. C++ will make up its mind how to interpret such a cast.
You could however come up with an intermediate type that shortens the syntax:
template <typename From>
struct Cast {
From from;
Cast(From const& from) : from(from) {}
template <typename To>
operator To() const {
return convert(from,To());
}
};
template <typename From>
Cast<From> cast(From const& from) {
return Cast<From>(from);
};
std::string convert(int, std::string const&);
This would allow you to convert things explicitly but without stating how exactly:
int i = 7;
std::string s = cast(i);
Related
I have a template function, within which I need to convert a const char * to my template value.
I know for a fact that this const char * was originally read from a ascii text file. My current code looks like this:
template <typename T>
bool Get(T &value, std::string const &query, T const &default)
{
const char* result = DataHandler.GetValue(query);
if (result != NULL)
{
value = static_cast<T>(result); //Here is the issue
return true;
}
value = default
return false;
}
Using this with an int as example i get the error
error C2440: 'static_cast' : cannot convert from 'const char *' to 'int'
Is there a way I can convert the char* to my type T seamlessly, I could not find an answer for this on SO.
In the worst case I can make a case for the 10 types I expect and give an error if not one of these, but I would rather not do it that way if possible.
Is there a way I can convert the char* to my type T seamlessly,
No.
There is no way to make conversion from string to a type automatically work with all types. Such conversion has to be implemented for each class. Typically, it is done by implementing the stream extraction operator >> for std::istream. The built in types such as int and some standard types such as std::string already have such operator. Then you can do for example:
std::istringstream istream(result);
int i;
istream >> i;
Without knowing exactly what you are asking for, using the answer given by #eerorika, here is a generic way to do the conversion:
#include <sstream>
#include <string>
#include <iostream>
template <typename T>
struct DefaultConverter
{
static T Convert(const char *result)
{
std::istringstream istream(result);
T i;
istream >> i;
return i;
}
};
template <typename T, typename Converter = DefaultConverter<T>>
bool Get(T &value, std::string const &query, T const &defaultVal)
{
const char* result = "100";
value = Converter::Convert(result);
return true;
}
int main()
{
int test = 10;
Get(test, "abc123", test);
std::cout << test;
}
The code referring to the DataHandler function is not important to illustrate what the above does.
Basically, the Get function takes an additional argument, namely a conversion template that has an available Convert function that can be called by Get. Note that the default converter simply uses the code as illustrated in the previous answer given by #eerorika.
This gives you the flexibility of providing your own converter that has a Convert function that can do anything customized.
For example:
struct SomeMPEGObject
{
SomeMPEGObject() {}
SomeMPEGObject(const char *) {}
};
struct MPEGConverter
{
static SomeMPEGObject Convert(const char *result)
{
return SomeMPEGObject(result);
}
};
//...
SomeMPEGObject mpeg;
Get<SomeMPEGObject, MPEGConverter>(mpeg, "12345", mpeg);
This will work without changing any code in the Get function.
So I was wondering if I could do something like the following in C++.
#include <string>
using namespace std;
class foo
{
public:
string bar;
string baz;
foo(const string &faz)
:bar(faz)
{
};
};
int main()
{
const foo foo1("somestring");
bool isTrue = ((std::string(foo1) == "some string");//This should be true
return 0;
}
How would I make std::string(foo1) equal "some string"? Is there some special variable name I need to use? Or is there something else I need to be doing? Please tell me if you know
You've basically got 2 options:
add a conversion operator, so that a foo can implicitly convert to string
define operator== for foo.
The first option may seem attractive at first, but code that uses conversion operators can quickly get out of hand - overload resolution is tricky enough as it is without adding more possible pathways.
The operator== version is quite simple (note, by making it a non-member you allow the char array to appear on the left of the ==):
bool operator==( foo const &f1, foo const &f2 )
{
return f1.bar == f2.bar;
}
You would use it like:
bool isTrue = (foo1 == "some string");
This matches char arrays because foo has a converting constructor, and the implicit conversion chain of char[] -> char * -> const std::string & happens.
I am learning C++ templates.I created a template class for addition of two strings
but I'm getting folloing error: Please help me to understand this error.
main.cc:65:52: error: no matching function for call to TheNameHolder<std::basic_string<char> >::TheNameHolder(const char [8], const char [7])
using namespace std;
template <class T>
class TheNameHolder{
T *a, *b;
public:
TheNameHolder(T *first, T *last)
{
a= first;
b= last;
}
T getName();
};
template <class T>
T TheNameHolder<T> :: getName()
{
T returnVal;
returnVal = strcat (returnVal,a);
returnVal = strcat (returnVal, " ");
returnVal = strcat (returnVal, b);
return returnVal;
}
int main()
{
TheNameHolder <string> obj ("Hi", "");
cout << obj.getName ();
return 0;
}
What? No. This isn't what templates are used for
You use strcat on your templated objects (actually, on T*, so on pointers to your object)
strcat accepts only char *. So T has to be char for it to work. If you know T is char, then it isn't a template as you know what it is. (btw - you have another bug that returnval should be T*, and you are using it uninitialized)
You seem to miss the whole concept of templates - which is OK since you are learning.
See - the sentence "I want to use templates to add two strings" is wrong - as you don't have any unknowns! You want to add 2 strings, you know what your type is. It isn't template.
Template would be "I want to add two lists of an unknown type" (then you can't use strcat obviously, nor can you assume your lists are "zero delimited" as that is only true for c style strings).
Your template parameter is std::string, so your constructor
TheNameHolder(T *first, T *last)
expects two pointers to std::string. You are passing it const arrays of char (string literals). It seems to me you can express everything in terms of std::string:
template <class T>
class TheNameHolder{
T a, b;
public:
TheNameHolder(const T& first, const T& last) : a(first), b(last)
{
}
T getName() { return a + " " + b; }
};
int main()
{
TheNameHolder<std::string> obj("Hi", "");
std::cout << obj.getName();
}
Note it isn't completely clear whether you need a class template here. The only advantage of this is that you can also use std::wstring or any other string type that supports initialization from a string literal and the + operator.
As was stated above, this would be the wrong place to use templates since you already know the data type. However, in the case where you may actually wish to "add two lists of an unknown type", you can use template specializations to deal with specific (in this case non-numeric) data types such as strings.
You would specialize this template as follows:
template <>
class TheNameHolder <std::string> {
...
};
I have written some code to cast const char* to int by using constexpr and thus I can use a const char* as a template argument. Here is the code:
#include <iostream>
class conststr
{
public:
template<std::size_t N>
constexpr conststr(const char(&STR)[N])
:string(STR), size(N-1)
{}
constexpr conststr(const char* STR, std::size_t N)
:string(STR), size(N)
{}
constexpr char operator[](std::size_t n)
{
return n < size ? string[n] : 0;
}
constexpr std::size_t get_size()
{
return size;
}
constexpr const char* get_string()
{
return string;
}
//This method is related with Fowler–Noll–Vo hash function
constexpr unsigned hash(int n=0, unsigned h=2166136261)
{
return n == size ? h : hash(n+1,(h * 16777619) ^ (string[n]));
}
private:
const char* string;
std::size_t size;
};
// output function that requires a compile-time constant, for testing
template<int N> struct OUT
{
OUT() { std::cout << N << '\n'; }
};
int constexpr operator "" _const(const char* str, size_t sz)
{
return conststr(str,sz).hash();
}
int main()
{
OUT<"A dummy string"_const> out;
OUT<"A very long template parameter as a const char*"_const> out2;
}
In this example code, type of out is OUT<1494474505> and type of out2 is OUT<106227495>. Magic behind this code is conststr::hash() it is a constexpr recursion that uses FNV Hash function. And thus it creates an integral hash for const char* which is hopefully a unique one.
I have some questions about this method:
Is this a safe approach to use? Or can this approach be an evil in a specific use?
Can you write a better hash function that creates different integer for each string without being limited to a number of chars? (in my method, the length is long enough)
Can you write a code that implicitly casts const char* to int constexpr via conststr and thus we will not need aesthetically ugly (and also time consumer) _const user-defined string literal? For example OUT<"String"> will be legal (and cast "String" to integer).
Any help will be appreciated, thanks a lot.
Although your method is very interesting, it is not really a way to pass a string literal as a template argument. In fact, it is a generator of template argument based on string literal, which is not the same: you cannot retrieve string from hashed_string... It kinda defeats the whole interest of string literals in templates.
EDIT : the following was right when the hash used was the weighted sum of the letters, which is not the case after the edit of the OP.
You can also have problems with your hash function, as stated by mitchnull's answer. This may be another big problem with your method, the collisions. For example:
// Both outputs 3721
OUT<"0 silent"_const> out;
OUT<"7 listen"_const> out2;
As far as I know, you cannot pass a string literal in a template argument straightforwardly in the current standard. However, you can "fake" it. Here's what I use in general:
struct string_holder //
{ // All of this can be heavily optimized by
static const char* asString() // the compiler. It is also easy to generate
{ // with a macro.
return "Hello world!"; //
} //
}; //
Then, I pass the "fake string literal" via a type argument:
template<typename str>
struct out
{
out()
{
std::cout << str::asString() << "\n";
}
};
EDIT2: you said in the comments you used this to distinguish between several specializations of a class template. The method you showed is valid for that, but you can also use tags:
// tags
struct myTag {};
struct Long {};
struct Float {};
// class template
template<typename tag>
struct Integer
{
// ...
};
template<> struct Integer<Long> { /* ... */ };
// use
Integer<Long> ...; // those are 2
Integer<Float> ...; // different types
Here is the pattern that I am using for template const string parameters.
class F {
static constexpr const char conststr[]= "some const string";
TemplateObject<conststr> instance;
};
see :
https://stackoverflow.com/a/18031951/782168
I'm reading the article at :
http://www.codeproject.com/Articles/257589/An-Idiots-Guide-to-Cplusplus-Templates-Part-1
and i don't understand some point.
OKAY .How can "Convert" convert itself to any data type?
What does the float() and double() mean at the end of lines below ?? How can converting happen?Could you please explain it with details?
Convert<int>::operator<float> float();
Convert<int>::operator<double> double();
For those of you who wants related part of the article , I'm copy pasting it below and the related part to my question is at the end .
For sure, 'explicit template argument specification' with method template is also possible. Consider another example:
template<class T>
class Convert
{
T data;
public:
Convert(const T& tData = T()) : data(tData)
{ }
template<class C>
bool IsEqualTo( const C& other ) const
{
return data == other;
}
};
Which can be utilized as:
Convert<int> Data;
float Data2 = 1 ;
bool b = Data.IsEqualTo(Data2);
It instantiates Convert::IsEqualTo with float parameter. Explicit specification, as given below, would instantiate it with double:
bool b = Data.IsEqualTo<double>(Data2);
One of the astounding thing, with the help of templates, you can do it by defining conversion operator on top of template!
template<class T>
operator T() const
{
return data;
}
It would make possible to convert the Convert' class template instance into any type, whenever possible. Consider following usage example:
Convert<int> IntData(40);
float FloatData;
double DoubleData;
FloatData = IntData;
DoubleData = IntData;
Which would instantiate following two methods (fully qualified names):
Convert<int>::operator<float> float();
Convert<int>::operator<double> double();
On one hand it provides good flexibility, since without writing extra code, Convert can convert itself (the specific instantiation) to any data-type - whenever conversion is possible at compilation level. If conversion is not possible, like from double to string-type, it would raise an error.
A class type can have user-defined conversions. This allows you to convert an instance of the class into another type. For example, here we have a struct that when converted to an int always has the value 42:
struct A {
operator int() { return 42; }
};
This is a special function, operator int, that is called for conversion to an int. Now if we have an instance of A, a, we can easily convert it to an int:
A a;
int x = a; // x now has the value 42
In the article, they are showing how you can use templates to generate a conversion operator for any type. The function template is defined as:
template<class T>
operator T() const
{
return data;
}
Now, for whenever you try to convert your object into another type, a new version of that function will be generated, replacing T with the type that you're converting to. So if we do float f = a, the following function will generated:
operator float() const
{
return data;
}
This is a function that returns the internal data as a float.
The two lines in the article that are confusing you are just showing you which functions would be generated by the example:
Convert<int>::operator<float> float();
Convert<int>::operator<double> double();
The first is operator float that converts to a float. The second is operator double that converts to a double.