I seem to be getting an error in the below code when I attempt to cast to a template of class T, when T is of type float. I have realized already that a type of int functions correctly, because the following is valid syntax:
char* str = "3";
int num = (int)str;
The same is not true of float. I'm wondering if there is a way to stop the g++ compiler erroring on a type mismatch so I can handle it with the RTTI method typeid().
class LuaConfig {
// Rest of code omitted...
// template currently supports both string and int
template <class T> T getC(const char *key) {
lua_pushstring(luaState, key);
lua_gettable(luaState, -2);
if (!lua_isnumber(luaState, -1)) {
// throw error
std::cout << "NOT A NUMBER" << std::endl;
}
T res;
// WHERE THE PROBLEM IS:
if ( typeid(T) == typeid(int)
|| typeid(T) == typeid(float)
) {
std::cout << "AS NUM" << std::endl;
// Floats should fall in here, but never does because of the
// else clause failing at compile time.
res = (T)lua_tonumber(luaState, -1);
} else {
// TODO: Fails on float here, it should fall down the
// first branch (above). This branch should only be for string data.
std::cout << "AS STRING" << std::endl;
res = (T)lua_tostring(luaState, -1); // LINE THAT CAUSES ISSUE.
}
std::cout << "OUT:" << res << std::endl;
lua_pop(luaState, 1);
return res;
}
}
int main( int argc, char* args[] ) {
LuaConfig *conf = new LuaConfig();
std::cout << conf->getC<int>("width") << std::endl;
std::cout << conf->getC<float>("width") << std::endl; // This causes the error.
}
The error g++ throws is:
source/Main.cpp:128: error: invalid cast from type ‘char*’ to type ‘float’
Try to avoid C-style casts. If you write (int)ptr where ptr is some pointer this will be a reinterpret_cast which is probably not what you want. For converting numbers to strings and back again check various FAQs. One way to do this is to use the std::stringstream class.
A C-style cast is dangerous because it can be used for lots of things and it's not always apparent what it does. C++ offers alternatives (static_cast, dynamic_cast, const_cast, reinterpret_cast) and a functional-style cast which is equivalent to a static cast).
In the case of (int)ptr it converts the pointer to an int and not the string representation of a number the pointer points to.
You might also want to check out Boost's lexical_cast.
Edit: Don't use typeid for this. You can handle this completely at compile-time:
template<typename T> struct doit; // no definition
template<> struct doit<int> {
static void foo() {
// action 1 for ints
}
};
template<> struct doit<float> {
static void foo() {
// action 2 for floats
}
};
....
template<typename T> void blah(T x) {
// common stuff
doit<T>::foo(); // specific stuff
// common stuff
}
In case T is neither int nor float you get a compile-time error. I hope you get the idea.
You need branching at compile time. Change the content in your template to something like this:
template<typename T> struct id { };
// template currently supports both string and int
template <class T> T getC(const char *key) {
lua_pushstring(luaState, key);
lua_gettable(luaState, -2);
if (!lua_isnumber(luaState, -1)) {
// throw error
std::cout << "NOT A NUMBER" << std::endl;
}
T res = getCConvert(luaState, -1, id<T>())
std::cout << "OUT:" << res << std::endl;
lua_pop(luaState, 1);
return res;
}
// make the general version convert to string
template<typename T>
T getCConvert(LuaState s, int i, id<T>) {
return (T)lua_tostring(s, i);
}
// special versions for numbers
float getCConvert(LuaState s, int i, id<int>) {
return (float)lua_tonumber(s, i);
}
int getCConvert(LuaState s, int i, id<float>) {
return (int)lua_tonumber(s, i);
}
There are a couple of alternative ways to solve this. To avoid repeatedly adding overloads, boost::enable_if could be useful. But as long as you have only two special cases for int and float, i would keep it simple and just repeat that one call to lua_tonumber.
Another pattern that avoids enable_if and still avoids repeating the overloads is to introduce a hierarchy of type flags - change id to the following, and keep the code within getC the same as above. I would use this if there tends to be more cases that need special handling:
template<typename T> struct tostring { };
template<typename T> struct tonumber { };
template<typename T> struct id : tostring<T> { };
template<> struct id<int> : tonumber<int> { };
template<> struct id<float> : tonumber<float> { };
id needs to be defined outside the class template now, because you cannot explicitly specialize it within the template. Then change the overloads of the helper function to the following
// make the general version convert to string
template<typename T>
T getCConvert(LuaState s, int i, tostring<T>) {
return (T)lua_tostring(s, i);
}
// special versions for numbers
template<typename T>
T getCConvert(LuaState s, int i, tonumber<T>) {
return (T)lua_tonumber(s, i);
}
The specializations would then determine the "configuration" of what should use strings and what number conversion.
I'm not familiar with Lua, but I don't think it matters in this case...
The return of lua_toString is clearly a char* which means that you're getting the address of the value and then attempting to convert that address to a float. Have a look at strtod to see how to do this more correctly or, as sellibitze noted, use a stringstream.
I never touched lua or its engine before, but it seems to me that you are misusing lua_tostring. This is its signature:
const char *lua_tostring (lua_State *L, int index);
Obviously, this function returns a const char*. In case of T == int, C/C++ allow what is called reinterpret_cast from a pointer into int. This conversion is meaningless in case of T == float. I think you have to take the returned c-string, then convert it into a number using atoi or atof depending on the type. The problem happens here:
res = (T)lua_tonumber(luaState, -1);
Because as we said, pointers can be converted into integers in C/C++ in a meaningful way, unlike floats.
Using memcpy() to make the assignment will avoid the compiler error.
char *str = lua_tostring(luaState, -1)
memcpy(&res, &str, sizeof(res));
However, the string returned by lua_tostring() is no longer valid after the call to lua_pop(). The string really needs to be copied into another buffer.
Even though the Lua website says that, and it makes logical sense, when testing I found that the pointer remained valid even after the state was closed. While he's right that you really should copy the string if you want to keep it around after your Lua function returns, it's probably not his problem.
Related
I have a class containing a string member variable and am trying to write a template function that will allow me to convert the string to another type. As a simplified example, without templates this is what I would do.
struct A {
std::vector<std::string> tokens;
};
void Test(const A& a) {
// Get the final token value as an int, or default to 42.
int i = a.tokens.empty() ? 42 : std::stoi(*a.tokens.rbegin());
}
This however has gotten tedious to write in as many places as I'm trying to get the final token and parse it, so I've written the following to assist.
struct A {
std::vector<std::string> tokens;
const string& GetLast(const string& defaul = "") {
return tokens.empty() ? defaul : *tokens.rbegin();
}
int GetLast(int defaul) {
return tokens.empty() ? defaul : std::stoi(*tokens.rbegin());
}
float GetLast(float defaul) {
return tokens.empty() ? defaul : std::stof(*tokens.rbegin());
}
};
void Test(const A& a) {
int i = a.GetLast(42);
}
This works fine but it just seems to be asking to be made into a template and allow conversion to any sort of type, provided a converter function is provided. I can't seem to find a generic solution that works, however. The following is the closest thing I can think of that should work, but I constantly get compiler errors that the template types can't be deduced.
template <typename T, typename Converter, typename... Args>
T GetLastAs(T defaul, Args ...args)
{
return tokens.empty() ? defaul : Converter(*tokens.rbegin(), args...);
}
with usage a.GetLastAs<float, std::stof>(42.0f)
Is there a generic solution to this problem, or is that just wishful thinking on my part?
Edit:
I've also gotten close with the following implementation:
template<class Converter, typename T, typename ...Args>
T GetLast(T defaul, Args ...args, Converter f = Converter()) const
{
return tokens.empty() ? defaul : f(*tokens.rbegin(), args...);
}
with a converter structure defined as struct ToInt { int operator()(const std::string& str) { return std::stoi(str); } };
and a usage of a.GetLast<ToInt>(42); or a.GetLast(42, ToInt());
But I cannot replace the ToInt in the usage to std::stoi and I believe the reason may be because stoi has an overload to take wstring instead of string and the GetLast method cannot figure out which overload to use. I don't know if it's even possible to specify which overload to use.
You can use a stringstream to extract values of default constructible types like this:
#include <string>
#include <sstream>
#include <iostream>
template <typename T>
T GetAs(const std::string& s) {
std::stringstream ss{s};
T t;
ss >> t;
return t;
}
int main() {
std::string s{"3.5"};
std::cout << GetAs<int>(s) << "\n";
std::cout << GetAs<double>(s) << "\n";
std::cout << GetAs<std::string>(s) << "\n";
}
I put the default and the fact that the string is element of a vector aside, because that isnt essential for the solution.
You could put the string into an std::istringstream and extract the value into a variable using the >> operator.
As in
T value{};
std::istringstream{ string_to_convert } >> value;
Of course, this requires T to be default-constructible, as well as there being an >> operator defined for T.
IIRC this is how Boost lexical cast works (or at least used to work). If you already using Boost in your project, I suggest you use its lexical cast library instead of making your own.
Or for more generic conversion (if you're using Boost) Boost convert. Which can handle different numeric bases.
From this SO topic (and this blog post), I know how to access Nth type in a template parameter pack. For instance, one of the answers to the abovementioned SO question suggests this:
template<int N, typename... Ts> using NthTypeOf = typename std::tuple_element<N, std::tuple<Ts...>>::type;
using ThirdType = NthTypeOf<2, Ts...>;
However, these methods work only in compile-time. Trying to do something such as:
int argumentNumber = 2;
using ItsType = NthTypeOf<argumentNumber, Arguments...>;
would result in compile error:
Error : non-type template argument is not a constant expression
Is there a way to access Nth type at runtime?
Here's my use case:
My program reads a text file, which is basically an array of numbers. Each number i refers to the i-th type of a template parameter pack that my class is templated based on. Based on that type, I want to declare a variable of that type and do something differently with it. For example, if it's a string, I want to declare a string and do string matching, and if it's an integer, I would like to compute the square root of a number.
C++ is a statically typed language. As such the type of all variables needs to be known at compile time (and cannot vary). You want a type that depends on a runtime value. Luckily C++ also features dynamic typing of objects.
Warning: all code in this answer serves only for demonstration of the basic concept/idea. It's missing any kind of error handling, sane interfaces (constructors...), exception safety, ... . So don't use for production, consider using the implementations available from boost.
To use this feature you need what's called a polymorphic base class: a class with (at least) one virtual member function from which you derive further classes.
struct value_base {
// you want to be able to make copies
virtual std::unique_ptr<value_base> copy_me() const = 0;
virtual ~value_base () {}
};
template<typename Value_Type>
struct value_of : value_base {
Value_Type value;
std::unique_ptr<value_base> copy_me() const {
return new value_of {value};
}
};
You can then have a variable with static type of pointer or reference to that base class, which can point to/reference objects from both the base class as well as from any of those derived classes. If you have a clearly defined interface, then encode that as virtual member functions (think of Shape and area (), name (), ... functions) and make calls through that base class pointer/reference (as shown in the other answer). Otherwise use a (hidden) dynamic cast to obtain a pointer/reference with static type of the dynamic type:
struct any {
std:: unique_ptr<value_base> value_container;
// Add constructor
any(any const & a)
: value_container (a.value_container->copy_me ())
{}
// Move constructor
template<typename T>
T & get() {
value_of<T> * typed_container
= dynamic_cast<value_of<T> *>(value_container.get();)
if (typed_container == nullptr) {
// Stores another type, handle failure
}
return typed_container->value;
}
// T const & get() const;
// with same content as above
};
template<typename T, typename... Args>
any make_any (Args... && args) {
// Raw new, not good, add proper exception handling like make_unique (C++14?)
return {new T(std:: forward<Args>(args)...)};
}
Since object construction is done at runtime the actual type of the pointed to/referenced object may depend on runtime values:
template<typename T>
any read_and_construct (std:: istream & in) {
T value;
// Add error handling please
in >> value;
return make_any<T>(std:: move (value));
}
// ...
// missing: way of error handling
std::map<int, std:: function<any(std:: istream &)>> construction_map;
construction_map.insert(std::make_pair(1, read_and_construct<double>));
// and more
int integer_encoded_type;
// error handling please
cin >> integer_encoded_type;
// error handling please
any value = construction_map [integer_encoded_type] (cin);
As you may have noticed above code uses also a clearly defined interface for construction. If you don't intend to do lots of different things with the returned any objects, potentially storing them in various data structures over great parts of the time your program is running, then using an any type is most likely overkill and you should just put the type dependent code into those construction functions, too.
A serious drawback of such an any class is its generality: it's possible to store just about any type within it. This means that the (maximum) size of the (actually) stored object is not known during compilation, making use of storage with automatic duration (the "stack") impossible (in standard C++). This may lead to expensive usage of dynamic memory (the "heap"), which is considerably slower than automatic memory. This issue will surface whenever many copies of any objects have to be made, but is probably irrelevant (except for cache locality) if you just keep a collection of them around.
Thus, if you know at compile time the set of types which you must be able to store, then you can (at compile time) compute the maximum size needed, use a static array of that size and construct your objects inside that array (since C++11 you can achieve the same with a (recursive template) union, too):
constexpr size_t max_two (size_t a, size_t b) {
return (a > b) ? a : b;
}
template<size_t size, size_t... sizes>
constexpr size_t max_of() {
return max_two (size, max_of<sizes>());
}
template<typename... Types>
struct variant {
alignas(value_of<Types>...) char buffer[max_of<sizeof (value_of<Types>)...>()];
value_base * active;
// Construct an empty variant
variant () : active (nullptr)
{}
// Copy and move constructor still missing!
~variant() {
if (active) {
active->~value_base ();
}
}
template<typename T, typename... Args>
void emplace (Args... && args) {
if (active) {
active->~value_base ();
}
active = new (buffer) T(std:: forward<Args>(args)...);
}
};
C++ is a statically-typed language, which means that the types of variables cannot be decided or changed at runtime.
Because your array of numbers are input at runtime, it's impossible for you to use the NthTypeOf metafunction in the manner you describe, because NthTypeOf can only depend on a compile-time index.
In your use case, not only are the variables of different type, but the behavior is also different based on user input.
If you want different behavior based on a value determined at runtime, I suggest either a switch statement, a container of std::function, or a heterogeneous container of polymorphic "command" objects.
A solution based on a switch statement is pretty trivial, so I won't bother showing an example.
A std::function is a polymorphic wrapper around a function-like object. You can use a container of std::function to build a sort of dispatch table.
struct StringMatch
{
void operator()() const
{
std::string s1, s2;
std::cin >> s1 >> s2;
if (s1 == s2)
std::cout << "Strings match\n";
else
std::cout << "Strings don't match\n";
}
};
struct SquareRoot
{
void operator()() const
{
float x = 0;
std::cin >> x;
std::cout << "Square root is " << std::sqrt(x) <<"\n";
}
};
int main()
{
const std::map<int, std::function> commands =
{
{1, StringMatch()},
{2, SquareRoot()},
};
int commandId = 0;
std::cin >> commandId;
auto found = command.find(commandId);
if (found != commands.end())
(*found->second)();
else
std::cout << "Unknown command";
return 0;
}
The map can of course be replaced by a flat array or vector, but then you need to worry about "holes" in the command ID range.
If you need your command objects to be able to do more then execute themselves (like having properties, or support undo/redo), you can use a solution that uses polymorphism and is inspired by the traditional Command Pattern.
class Command
{
public:
virtual ~Command() {}
virtual void execute();
virtual std::string name() const;
virtual std::string description() const;
};
class StringMatch : public Command
{
public:
void execute() override
{
std::string s1, s2;
std::cin >> s1 >> s2;
if (s1 == s2)
std::cout << "Strings match\n";
else
std::cout << "Strings don't match\n";
}
std::string name() const override {return "StringMatch";}
std::string description() const override {return "Matches strings";}
};
class SquareRoot : public Command
{
public:
void execute() override
{
float x = 0;
std::cin >> x;
std::cout << "Square root is " << std::sqrt(x) <<"\n";
}
std::string name() const override {return "SquareRoot";}
std::string description() const override {return "Computes square root";}
};
int main()
{
constexpr int helpCommandId = 0;
const std::map<int, std::shared_ptr<Command>> commands =
{
{1, std::make_shared<StringMatch>()},
{2, std::make_shared<SquareRoot>()},
};
int commandId = 0;
std::cin >> commandId;
if (commandId == helpCommandId)
{
// Display command properties
for (const auto& kv : commands)
{
int id = kv.first;
const Command& cmd = *kv.second;
std::cout << id << ") " << cmd.name() << ": " << cmd.description()
<< "\n";
}
}
else
{
auto found = command.find(commandId);
if (found != commands.end())
found->second->execute();
else
std::cout << "Unknown command";
}
return 0;
}
Despite C++ being a statically-typed language, there are ways to emulate Javascript-style dynamic variables, such as the JSON for Modern C++ library or Boost.Variant.
Boost.Any can also be used for type erasure of your command arguments, and your command objects/functions would know how to downcast them back to their static types.
But such emulated dynamic variables will not address your need to have different behavior based on user/file input.
One possible approach when you want to do something with a run-time dependent type very locally, is to predict run-time values at the compile time.
using Tuple = std::tuple<int, double, char>;
int type;
std::cin >> type;
switch(type) {
case 0: {
using ItsType = std::tuple_element<0, Tuple>;
break;
}
case 1: {
using ItsType = std::tuple_element<1, Tuple>;
break;
}
default: std::cerr << "char is not handled yet." << std::endl;
break;
}
Only works with small type packs, of course.
Is there a way to access Nth type at runtime?
Yes, although per other answers, it may not be appropriate in this context.
Adapting this answer, you can iterate at compile time, and choose a type.
#include <iostream>
#include <fstream>
#include <string>
#include <type_traits>
#include <tuple>
#include <cmath>
std::ifstream in("my.txt");
void do_something(const std::string& x)
{
std::cout << "Match " << x << '\n';
}
void do_something(int x)
{
std::cout << "Sqrt of " << x << " = " << std::sqrt(x) << '\n';
}
template<std::size_t I, typename... Tp>
inline typename std::enable_if_t<I == sizeof...(Tp)> action_on_index_impl(size_t)
{ // reached end with I==number of types: do nothing
}
template<std::size_t I, typename... Tp>
inline typename std::enable_if_t<I < sizeof...(Tp)> action_on_index_impl(size_t i)
{
if (i == I){
// thanks to https://stackoverflow.com/a/29729001/834521 for following
std::tuple_element_t<I, std::tuple<Tp...>> x{};
in >> x;
do_something(x);
}
else
action_on_index_impl<I+1, Tp...>(i);
}
template<typename... Tp> void action_on_index(size_t i)
{
// start at the beginning with I=0
action_on_index_impl<0, Tp...>(i);
}
int main()
{
int i{};
while(in >> i, in)
action_on_index<std::string, int>(i);
return 0;
}
with my.txt
0 hello
1 9
0 world
1 4
output
Match hello
Sqrt of 9 = 3
Match world
Sqrt of 4 = 2
I needed to know how to access Nth type at runtime in a different context, hence my answer here (I wonder if there is a better way, particularly in C++14/17).
i have object
template <class FLOAT>
struct Cstruct {
Struct1<FLOAT> _var1;
Struct2<FLOAT> _var2;
Cstruct(){};
Cstruct(Struct1 var1,Struct2 var2):_var1(var1),_var2(var2){};
};
FLOAT can be "double" or "int". Struct1 and Struct2 are also templatized with FLOAT.
now i also have a global variable declared
Cstruct<double> globalObj_d;Cstruct<int> globalObj_i;
inside main() i have
main(){
// some code
if double then call func<double>();
if int then call func<int>();
}
and inside templatized func() i have
template<class FLOAT> void func(){
// some code
Struct1<FLOAT> var1;
Struct2<FLOAT> var2;
Cstruct<FLOAT> localObj(var1,var2);
// now i want to assign "localObj" to the global object "globalObj_d"
if double then
globalObj_d = localObj;
if int then
globalObj_i = localObj;
}
and i get an error saying
error C2679: binary '=' : no operator found which takes a right-hand operand of type 'Cstruct<FLOAT>
does does this mean i have to explicitly write an "operator=" inside Cstruct ? my understading of templatized and global object it seems is kind of flawed. any help will greatly appreciated.
In this case you might need to. See the rule of three The compiler will provide one for you if it can. You have not showed us the definitions of Struct1<FLOAT> or Struct2<FLOAT>. If it can't generate assignments for these, it can't generate one for CStruct.
While you are there, avoid the leading underscores on the variable names .
The use of psudocode in your question make it difficult to understand. So let me try to boil this down a little bit in to real code. It appears that what you are trying to do is essentially something along these lines:
template <typename VAL>
class Foo
{
public:
VAL mVal;
};
int main()
{
Foo <int> global_i;
Foo <double> global_d;
Foo <double> local;
// ...
if (/*someConditional*/)
global_i = local; // <== LINE 1
else
global_d = local; // <== LINE 2
}
This won't work. Note that even though only one of either LINE1 or LINE2are executed at run-time, they are both compiled at compile-time. The first one is trying to assign a Foo<int> to a Foo<double>, but the types are not compatible much in the same way that these are also not compatible:
class Gee
{
};
class Whiz
{
};
int main()
{
Gee g;
Whiz w;
Gee local;
local = w; // <<< INCOMPATIBLE TYPES
}
In order to make this work, you will either need to provide some kind of conversion operator on Foo to convert to another type of Foo, for example:
template <typename VAL>
class Foo
{
public:
template <typename OTHER> operator Foo <OTHER> () const
{
Foo <OTHER> ret;
// ...
return ret;
}
};
...or perhaps provide two separate functions to do the assignments; one for a Foo<int>, and another for a Foo<double>.
First: if a type might be either floating point or integer, don't name it "FLOAT". You could use the standard T, or perhaps something like Number, but definitely avoid FLOAT.
As to the real question (or my guess at the real question): almost any time you think in terms of if (type == X) or switch (type) sort of code (at least in C++), you're making a fundamental mistake -- you can probably manage to do that if you want to badly enough, but it's not how C++ is intended to work.
In this case, there's a fairly easy way to avoid it: create another template. In particular, you can overload a couple of function templates, one for each global you want to support:
#include <string>
#include <iostream>
int i_global;
double d_global;
template <class T>
void assign(T in) {
// this function should never be called.
assert(false);
}
template<>
void assign<int>(int in) {
i_global = in;
}
template<>
void assign<double>(double in) {
d_global = in;
}
// for the moment, func(input) will just call assign(input):
template <class T>
void func(T input) {
assign<T>(input);
}
int main(int argc, char **argv) {
if (argc != 2) {
std::cerr << "Usage: trash <number>\n";
return EXIT_FAILURE;
}
std::string in(argv[1]);
// see if the input contains a decimal point, and act accordingly:
if (in.find('.') != std::string::npos)
func(std::stod(in));
else
func(std::stoi(in));
// show the results -- the values of the globals:
std::cout << "Result:\ndouble: " << d_global << "\nint: " << i_global << "\n";
return 0;
}
I get the result I'd hope for -- if I enter something like 1.5 it gets assigned to the double; if I enter something like 123 it gets assigned to the int.
UPDATE:
I went for the template approach cause it seemed the most elegant / concise but then I end up with stuff like this:
template<typename charType>
int doSomethingWithString(const charType* buffer)
{
wchar_t* tempBuffer = NULL;
if(typeid(charType) == typeid(char))
{
tempBuffer = (wchar_t*)malloc(sizeof(wchar_t)*strlen((char*)buffer));
mbstowcs(tempBuffer, (const char*)buffer, strlen((const char*)buffer));
}
else if(typeid(charType) == typeid(wchar_t))
{ tempBuffer = (wchar_t*)malloc(sizeof(wchar_t)*strlen((char*)buffer));
tempBuffer = wcscpy(tempBuffer, (const wchar_t*)buffer);
}
At which point I feel it's kind of ugly (specially since I still have to have all those casts there to let the compiler know). I also tried turning the parameter into a wstring but I just don't seem to find an appropriate constructor for both cases?
It's been a while now that I've been away from C++ and I can't remember the C++ way of going about this:
Let's say I have a class with some method myClass::doSomethingWithString(...) and I want the same method to be able to be called passing in a character sequence as either const char* or const wchar_t*. Was there a way to make the method be able to accept both types of "strings" and tell if the parameter is const char* or const wchar_t* inside the method implementation? Or is method overloading the only way to go about it?
Method overloading is the only way to go about it.
Alternately, You could write a single template function.However, in that case the actions you perform inside the function would have to be same in either case. In this case the compiler will generate source code of the functions for your both the types.
Overloading is probably the best way to go about it, unless you're using another API that allows exactly the same syntax with both char* and wchar_t*.
void foo(char const *c) {
std::cout << c << '\n';
}
void foo(wchar_t const *c) {
std::wcout << c << L'\n';
}
You could also use templates. If the code doesn't actually change between char and wchar_t versions then you'll only have one version:
template<typename CharT>
void foo(CharT const *c) {
std::cout << "foo called\n";
}
But since doing anything useful usually involves using the argument, and using the argument usually requires different code (e.g. calling printf for char and wprintf for wchar_t) you'll have to have a version for each type. With a template you'd do that by specializing.
template<typename CharT>
void foo(CharT const *c);
template<> void foo<char>(char const *c) { /* char version */ }
template<> void foo<wchar_t>(wchar_t const *c) { /* wchar_t version */ }
Now, if you have an API that provides an identical interface for wchar_t and char via overloading or specializing, then templates let you build on top of that by having a single version for both types using the overloaded API:
// Given the above overloads/template specializations:
template<typename CharT>
void bar(CharT const *c) {
foo(c); // calls foo(char const *) or foo(wchar_t const *) as needed.
}
But since you're asking if there's a way to tell inside the function what the type is, it seems likely that you want to have different versions. In which case you're probably best off using overloads, or factoring the differences out into overloaded functions so the main function can be a single template.
There is another option that's probably a bad idea. Depending on the actual differences you might be able to have a single template and then do something like:
template<typename T>
int foo(T const *t) {
if(sizeof T == sizeof wchar_t) {
// wchar_t version
} else {
// char version
}
}
And someday C++ may adopt static_if in which case you'll be able to do:
template<typename T>
int foo(T const *t) {
static_if(std::is_same<T,wchar_t>::value) {
// wchar_t version
}
static_if(std::is_same<T,char>::value) {
// char version
}
}
char and wchar_t are different types, so are the pointers to them. Thus you cannot write one function that accepts both as there is no common "parent" (so to speak).
YOu can write a template function that accepts the type as a template parameter. In that case you still have two functionsin your binary program if you call it both with char* and wchar_t*, but in the cose you will see only one function body.
template<T> void someFunction(T* str) {
// your code here. Use T when you would use char or wchar_t in a regular function
}
You can use method overloading. I would also suggest using std::string and std::wstring for C++.
Example:
class MyClass
{
public:
void doSomethingWithString(std::string s)
{
std::cout << "String: " << s << std::endl;
}
void doSomethingWithString(std::wstring ws)
{
std::wcout << L"Wide String: " << ws << std::endl;
}
};
...
MyClass myClass;
myClass.doSomethingWithString("const char *");
myClass.doSomethingWithString(L"const wchar_t *");
Write a class that has implicit constructors for both kinds of arguments:
struct String {
String(const char*): called_with_wchar_t(false) { }
String(const wchar_t*): called_with_wchar_t(true) { }
bool called_with_wchar_t;
};
void function(const String&);
...
function("a");
function(L"a");
Or use Boost.Variant.
So i'm trying to create a pretty specific for my needs hashmap for a small project where i'm trying to learn c++. I have the following code:
template<class T>
class HashMap
{
public:
HashMap();
virtual ~HashMap();
void add(T value);
T get(T *value);
private:
int hash(T *data);
T _hashes[26]; //I want a fixed size here
};
template<class T>
HashMap<T>::HashMap()
{
for(int i = 0; i < 26; i++)
this->_hashes[i] = T();
}
template<class T>
HashMap<T>::~HashMap()
{
//Don't really have anything to delete here?
}
template<class T>
int HashMap<T>::hash(T *dat)
{
//Super simple, just to try things out
return (long int) dat % 26;
}
template<class T>
T HashMap<T>::get(T *val)
{
int idx = this->hash(val);
cout << idx << endl;
//Probably somewhere here i get my problem
if(this->_hashes[idx])
return this->_hashes[idx];
return T();
}
template<class T>
void HashMap<T>::add(T val)
{
//Should probably do some check if there's already an element here.
this->_hashes[this->hash(&val)] = val;
}
The problem im having is that this compiles fine but when I do something like this in my main.cpp:
HashMap<char> a = HashMap<char>();
a.add('h');
a.add('c');
a.add('g');
char *b = new char {'c'};
cout << a.get(b) << endl;
delete b;
It usually returns the id, ie:
4
and an empty line which is just a empty char. (the output of the function is in the get() method), but sometimes it will show me something like this:
18
g
instead of 18 and an empty line. My question is why this happens and how i can prevent it? Does it have something to do with memory not being 'nulled' when it's deleted but just free for other programs to take and then i don't initialise it correctly?
Also, if you have the time please point out any mistakes or not so good to do things in the code.
If it's of any interest im using GCC Debian 4.4.5-8 to compile and compile it with g++ -g file.cpp -o file
Thankful for any help!
The behavior you see is normal: if you get a value that you put in your hash, it will be displayed by your main. What is giving you surprising results is your hash function:
return (long int) dat % 26;
This hashes the dat pointer, not the T that dat points to. Try with:
return *dat % 26;
(Or just use a standard std::set.)
Another problem with your code:
T _hashes[26]; //I want a fixed size here (a
and
this->_hashes = new T[26]; (b
are incompatible. Either use the fixed array (a) and you don't need to allocate it (b), or use a plain pointer (T *_hashes) and do (b) - I'm surprised your compiler accepts what you have. If you use (a) you don't need anything in the destructor. If you use (b), you need to delete [] in your destructor.
Passing a T* in get but a T in set is a bit strange too.
Here's a more idiomatic c++ implementation:
#include <array>
#include <iostream>
#define MAGIC_NUMBER 26 //rename this to something else preferably
template<class T>
class HashMap
{
public:
HashMap();
virtual ~HashMap(){};
void add(T value);
T get(T *value);//potentially confusing that add and get take different types
private:
int hash(T *data);
std::array<T, MAGIC_NUMBER> _hashes; //I want a fixed size here
};
template<class T>
HashMap<T>::HashMap()
{
std::fill(_hashes.begin(),_hashes.end(), T());
}
template<class T>
int HashMap<T>::hash(T *dat)
{
//Super simple, just to try things out
return (static_cast<int>(*dat)) % MAGIC_NUMBER;//prefer using c++ casts
}
template<class T>
T HashMap<T>::get(T *val) //this is strange, you pass in a pointer and get a non-pointer
{
int idx = this->hash(val);
std::cout << idx << std::endl;
if(this->_hashes[idx])
return this->_hashes[idx];
return T();
}
template<class T>
void HashMap<T>::add(T val)
{
//Should probably do some check if there's already an element here.
this->_hashes[this->hash(&val)] = val;
}
int main(void){
HashMap<char> a = HashMap<char>();
a.add('h');
a.add('c');
a.add('g');
char *b = new char {'c'};
std::cout << a.get(b) << std::endl;
delete b;
}
Note you will need to compile with c++0x or c++11 features to get the usage of the std::array class. One of the main benefits of the array class is that you get more safety with the memory allocation than just a plain c-style array.
Right now you might want to reconsider some elements of the design. In particular it is confusing that add and get, have different types. Also this isn't what people generally think about when they hear hashmap, this structure is more like a set.
Also as a coding standards note, if you are prefixing your member variables it's a bit tautological to also use this-> to access them.