[C++] What's better?

Started by
8 comments, last by Mybowlcut 12 years, 10 months ago
GameDev source tags are crappy, so I have to use pastebin: http://pastebin.com/GZkbihzY

Which is more efficient if the input is a string?

Advertisement
GameDev source tags are almost identical:

[source lang="cpp"]
template<typename T>
std::string to_string(const T& t)
{
std::ostringstream oss;
oss << std::dec << t;
return oss.str();
}

template<typename T>
std::string to_string(const T& t)
{
if(!boost::is_base_and_derived<std::string, T>::value)
{
std::ostringstream oss;
oss << std::dec << t;
return oss.str();
}
return t;
}
[/source]

I'd say neither, a specialization for std::string would resolve at compile time. Since you are not supposed to derive from std::string, the following should be safe.

[source lang="cpp"]
template<>
std::string to_string<std::string>(const std::string &t)
{
return t;
}
[/source]

You could also specialize for const char* to do a direct std::string construction and skip the need for a stringstream.

Or you could just use boost::lexical_cast? Not sure, never used it but I understand it does the same thing.

GameDev source tags are almost identical:

[source lang="cpp"]
template<typename T>
std::string to_string(const T& t)
{
std::ostringstream oss;
oss << std::dec << t;
return oss.str();
}

template<typename T>
std::string to_string(const T& t)
{
if(!boost::is_base_and_derived<std::string, T>::value)
{
std::ostringstream oss;
oss << std::dec << t;
return oss.str();
}
return t;
}
[/source]

I'd say neither, a specialization for std::string would resolve at compile time. Since you are not supposed to derive from std::string, the following should be safe.

[source lang="cpp"]
template<>
std::string to_string<std::string>(const std::string &t)
{
return t;
}
[/source]

You could also specialize for const char* to do a direct std::string construction and skip the need for a stringstream.

Or you could just use boost::lexical_cast? Not sure, never used it but I understand it does the same thing.

When I was using the source tags, they didn't resolve to a code snippet, instead produced a bunch of HTML.

I hadn't thought about specialisation, cheers. :)

Edit: That won't work... it seems that unless I pass std::string as a template argument, it won't use the specialised function...

The following, compiled with g++:

[source lang="cpp"]
#include <iostream>

template<class T> void test(const T &t)
{
std::cout << "general\n";
}

template<> void test<std::string>(const std::string &t)
{
std::cout << "specialized\n";
}

int main()
{
std::string s="hello";

test(s);
test(23);
}
[/source]

Produces the output:


general
specialized


I can't figure out how to specialize for const char* though, as a literal string will call the general version, but I cannot specialize for const char* as it errors saying it does not match any template.

Template gurus to the rescue?

(BTW, new source tags are [ source lang="cpp" ] without spaces).
is_base_and_derived - you shouldn't be deriving from std::string. Are you?
Weird. Using VC10, the following has the same error:

[source lang="cpp"]

class x
{

template<class T> void test(const T &t) const
{
std::cout << "general\n";
}

template<> void test<std::string>(const std::string &t) const
{
std::cout << "specialized\n";
}

template<> void test<char*>(char *s) const
{
std::cout << "specialized for char*\n";
}

};
[/source]

But some old library code of mine compiles fine:

[source lang="cpp"]
class xcs::node
{
public:
/* snip */

template<class T> bool is() const;
template<> bool is<std::string>() const { return true; }

template<> bool is<char*>() const { return false; }
template<> bool is<const char*>() const { return false; }

/* snip */
};
[/source]

Buggered if I can see what the difference is.

The following, compiled with g++:

[source lang="cpp"]
#include <iostream>

template<class T> void test(const T &t)
{
std::cout << "general\n";
}

template<> void test<std::string>(const std::string &t)
{
std::cout << "specialized\n";
}

int main()
{
std::string s="hello";

test(s);
test(23);
}
[/source]

Produces the output:


general
specialized


I can't figure out how to specialize for const char* though, as a literal string will call the general version, but I cannot specialize for const char* as it errors saying it does not match any template.

Template gurus to the rescue?

(BTW, new source tags are [ source lang="cpp" ] without spaces).

I was just using [source][/source]... perhaps I had some subtle typo.

And you're right, that works perfectly, I mustn't have made the correct changes to my code to test it out. :x Full of mistakes today!


is_base_and_derived - you shouldn't be deriving from std::string. Are you?

No way! Haha! No, I just wanted a nice way to determine the type of an object - have no idea if that was the correct way, but from my googling it seemed like it would do the job.

Hmm... I seem to be getting linker warnings from these functions:

[source lang="cpp"]template<typename T>
std::string to_string(const T& t, std::ios_base& (*f)(std::ios_base&))
{
std::ostringstream oss;
oss << f << t;
return oss.str();
}

// Uses std::dec.
template<typename T>
std::string to_string(const T& t)
{
std::ostringstream oss;
oss << std::dec << t;
return oss.str();
}

// Specialised version that doesn't do any conversion.
template<>
std::string to_string<std::string>(const std::string& t)
{
return t;
}[/source]

Warning 5 warning LNK4006: "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl Conversions::to_string<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)" (??$to_string@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Conversions@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABV12@@Z) already defined in Triggered_Animation.obj; second definition ignored Toolbar.obj

etc...[/quote]

You need to inline the specialized version, as it's not really a template any more.

BTW, you don't even need template specialization here -- regular overloads will do: template<typename T> std::string to_string(const T& t)
{
std::ostringstream oss;
oss << std::dec << t;
return oss.str();
}
inline std::string to_string(const std::string& t)
{
return t;
}
inline std::string to_string(const char* t)
{
return t;
}
That works perfectly, thanks. :) Clearly I've still a lot to learn about templates haha...

This topic is closed to new replies.

Advertisement