How to Convert Typename T to String in C++

How to convert typename T to string in c++

There is no built-in mechanism for this.

typeid(T)::name() can give some info, but the standard does not mandate this string to be human-readable; just that it has to be distinct for each type. (E.x. Microsoft Visual C++ uses human-readable strings; GCC does not.)

You can build your own system though. For example, traits-based. Something like this:

// default implementation
template <typename T>
struct TypeName
{
static const char* Get()
{
return typeid(T).name();
}
};

// a specialization for each type of those you want to support
// and don't like the string returned by typeid
template <>
struct TypeName<int>
{
static const char* Get()
{
return "int";
}
};

// usage:
const char* name = TypeName<MyType>::Get();

How to get a templated typename as a string?

Templates don't work like that. In your template T specifies a type, and not a sequence of tokens:

typedef int lolztype;
typedef int lulztype;

function_foo<lolztype>(0, 0);
function_foo<lulztype>(0, 0); // calls the *same* template

There is no way to get lolztype or lulztype respectively. What you could try is using typeid(T).name(), but that isn't very helpful because it isn't required to be human readable and not even required to be distinct for each type.

You could try using geordi's file type_strings.hpp, which can print out a human readable string when compiled with GCC.

How to convert a template type to string if it can be a string too?

You could just provide a new overload for to_string

std::string to_string(const std::string& s) { return s; }

You could put the code above inside the class, as a private method, or inside a suitable namespace, so to avoid possible clashes when, say, somebody uses your code and wishes to write her/his own overload of to_string.

EDIT: As noted in the comments below, you cannot put such an overload in the std namespace, as a new declaration of std::to_string is forbidden, see Extending the namespace std.

EDIT: If you need to possibly call std::to_string, you may need to add an additional to_string template function to your code as

template <typename T>
typename std::enable_if<!std::is_convertible<T, std::string>::value, std::string>::type to_string(T r) const { return std::to_string(r); }

(Do not forget #include <type_traits> for that).

This is because, even if you import the standard library std::to_string by using namespace std, the member function to_string will have the priority. See the discussion: C++: Why member function has priority over global function. Here you can see a minimal example.

How to convert from any type to std::string in C++

There is no universal way to convert an object of arbitrary type to a string in C++. But the most commonly supported facility for outputting data as strings are output streams. So, you could use std::ostringstream like this:

std::string join(const char *seperator)
{
std::ostringstream strm;
auto curr = this->head;
while (curr)
{
strm << curr->value;
if (curr->next)
strm << seperator;
curr = curr->next;
}
return strm.str();
}

Note that for this to work the type T should provide an operator<< overload that takes std::ostream& as the first argument. All arithmetic types, C-style strings and std::string are supported by this facility, but not all user-defined types may be.

Can you use a string(or c string) as a typename

No. As far as I know, there is no provision in C++ for finding types from an in-language string of any kind.

As for your other problems:

  • A value template parameter must be constexpr: since C++11, you can use variables of some constexpr types as template parameters
  • Apparently you can use a constexpr string_view template parameter in C++17, and a constexpr string template parameter in C++20

Regardless of these other answers, you still can't turn those strings into types. That kind of operation is typical of dynamic languages, but C++ is a statically typed, compiled language. And, while it is possible to design a static language that can do that kind of operation at compile time, that is not the path that C++ design has taken.

I think it's reasonable to ask: why you want to do this in the first place? There is probably a better way to accomplish whatever prompted the question, but without further information it is hard to know how to help.


Edit, in response to updated question:

In order to read datastructures from a file, you will need do the string-to-type mapping yourself.

Generally, you will have some "driver" object where you register types that you want to create from your file, which it will then use when reading from the file.

The simplest way is to register each typename in association with a callback to construct the data. The most straightforward, object-oriented way to handle the resulting heterogeneous datastructures is to derive all their types from a common Readable base class.

Registration is where you will provide the typename to be used in the file. If you don't feel like repeating the typename with every registration line, you can use macros to do that -- something like:

#define REGISTER(type) (driver.register(#type, &(type)::construct))

(note that #name is the C preprocessor's "string-izing" syntax)

On the conversion from std::string type to template T type in C++

std::stringstream convert(...); is a constructor call, but trying to do convert(...); after the stream is created is illegal (it would require the stream to overload operator(), which it doesn't do). convert = std::stringstream(...) would work, but I'd just completely recreate the stream.

You also should use a read-only std::istringstream, since you never write anything to it.

I also made some cosmetic changes and ended up with following:

template <typename T>
[[nodiscard]] T getline_as(std::istream &s);

template <>
[[nodiscard]] std::string getline_as<std::string>(std::istream &s)
{
std::string str;
std::getline(s, str);
return str;
}

template <typename T>
[[nodiscard]] T getline_as(std::istream &s)
{
while (true)
{
T value{};
std::istringstream convert(getline_as<std::string>(s));
if (convert >> value)
return value;
}
}

C++ convert string to typename

Yes there is, but it requires manual code and that you know all the types that are going to appear in the file. That's because templates are compile time constructs and they cannot be instantiated at runtime.

You can always use the preprocessor or other tricks to try and reduce the boilerplate if you want to.

void callFoo(std::string type, std::any arg) {
if (type == "int")
foo<int>(std::any_cast<int>(arg));
else if (type == "double")
foo<double>(std::any_cast<double>(arg));
else if (type == "string")
foo<std::string>(std::any_cast<std::string>(arg));
}

Of course, this requires that you pass in the correct type (no implicit conversions!). I don't see any way to avoid that.



Related Topics



Leave a reply



Submit