1

I have a map loading function that takes input using ifstream from a file and creates objects from them.

Here is what the file might look like:

tree=50,100,"assets/tree.png"
box=10,10,"assets/box.png"

Which should create the objects tree and box and pass the values to their constructor. I already have the value part figured out, but I don't know how to take the string "tree" and create a tree object.

Is it possible to take a string(or c string) and use it as a type name?

Things I've tried:

  • Passing the string as a template typename

    #include <string>
    
    struct A {};
    
    template<typename T>
    T* createType() {
        T* type = new T()
        return T;
    }
    
    int main() {
        std::string tname = "A";
        auto* type = createType<tname>;
    }
    
  • Using the using keyword

    #include <string>
    
    template<std::string T>
    struct someType {}
    
    struct A {};
    struct B {};
    
    using someType<"A"> = A;
    using someType<"B"> = B;
    
    int main() {
        std::string tname1 = "A";
        std::string tname2 = "B";
        someType<tname1> typeA;
        someType<tname2> typeB;
    }
    

Problems:

  • I can't seem to find a clear answer about this but is seems like there are some problems with using a string as a template parameter.

  • I don't know if it is ok to pass a variable as a template parameter

  • I don't think that you can cast template types (from string to typename)

Is there any way that either of these, or some other way might work to accomplish this? Or is this just not possible?

  • 2
    what is the actual problem you are trying to solve? Once you can map strings to types, what would you do with it? – 463035818_is_not_an_ai Feb 17 '22 at 15:31
  • btw for non working code you should include the compiler error in the quesiton. The first cannot work because you mix template type argument with template non-type argument. The second doesn't make sense because `using` is to introduce a new alias for a type, not to "assign" one existing type to another already existing type – 463035818_is_not_an_ai Feb 17 '22 at 15:33
  • 4
    Values are not types. Strings are values, not identifiers, and there is no way to create an identifier from a string. Template arguments must be known at compile-time. You can't create types at runtime. (That last point alone should make it clear that you're barking up the wrong cul-de-sac without a paddle.) – molbdnilo Feb 17 '22 at 15:33
  • [xy problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) it is possible to establish a mapping between strings and types, but not like this and not out of the box. If you tell us about the actual problem you are trying to solve (instead of only about your attempted solution) maybe we can help – 463035818_is_not_an_ai Feb 17 '22 at 15:36
  • @463035818_is_not_a_number I edited my question to include the reason behind doing this – Gary Fisher Feb 17 '22 at 15:58
  • Once you have `someType typeA` (imagine for a second that this is legal), what do you plan to do with it? – n. m. could be an AI Feb 17 '22 at 16:03
  • 1
    look up the factory pattern. You could make `tree` and `box` inherit from some `shape` and then use a factory – 463035818_is_not_an_ai Feb 17 '22 at 16:17

1 Answers1

0

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)

comingstorm
  • 25,557
  • 3
  • 43
  • 67