0

I am trying to do this, but it can't compile.. What I want to do is define a template class specialization implementation. and create a type of it.. I can do it with int type, but I got a lot of trouble when I tried with string..

#include <iostream>

using namespace std;

template <char const *str>
struct X
{
};
constexpr char global_string[] = "String";

template<>
struct X<global_string>
{
    typedef int mytype;

    const char *GetString() const
    {
         return global_string;
    }
};


constexpr char version_use[] = "String";
int main()
{
    using X1= X<version_use>  ;
    X1::mytype t = 1;
    //X1 x;
    //cout<<x.GetString() << " " << t;
}
sh-4.2$ g++ -std=c++11 -o main *.cpp                                                                                                                                                                                               
main.cpp: In function 'int main()':                                                                                                                                                                                                
main.cpp:27:5: error: 'mytype' is not a member of 'X1 {aka X<((const char*)(& version_use))>}'                                                                                                                                     
     X1::mytype t = 1;                                                                                                                                                                                                             
     ^                                                                                                                                                                                                                             
main.cpp:27:16: error: expected ';' before 't'                                                                                                                                                                                     
     X1::mytype t = 1;      
HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
Bryan Fok
  • 3,277
  • 2
  • 31
  • 59

1 Answers1

0

Bryan asked for an example of using typeid. Here's something I made the other day as an experiment in compile time polymorphic data storage. The goal was to get elegant syntax at the client level to put "anything" (with some limits) into a list:

template <typename T> const char* Type() 
{ 
    static const char *s = typeid(T).name(); 
    return s; 
}

The template function + static variable ensures there's only one copy of this string generated per project. Then type name can be printed out or the value of the pointer for two objects can be compared at run-time. I made this as part of an experiment in dynamic type storing. I'll provide the code if anyone will be interested or to receive comments / criticism of this approach. Basically the below code creates a "nodeBase" object, then creates a "node < T >" which is a child class of the nodeBase. nodeBase itself is an abstract class, thus it's never created. All the real nodes are of the polymorphic node < T > types. The nodeBase forms a stack to which you can push items, and they can be of any type. One node < T > child class and one Type < T > function is created for each different type you try and store. Storing types is determined at compile time but the types can be correctly inferred from the collection at runtime. Note that std::any in the c++17 might make the below ideas obsolete:

// stores type string and used to compare types at runtime
template <typename T> const char* Type() { static const char *s = typeid(T).name(); return s; }

// nodeBase parent class, with virtual function Data
struct nodeBase
{
    nodeBase *next = 0;
    const char *type;
    int size;
    virtual ~nodeBase() {};
    virtual void *Data() = 0;
};

// child class for data structures that have copy constructors
template <typename T> struct node : public nodeBase // template for storing regular structs and stuff
{
    T data;
    node(T _data) : data(_data)
    {
        type = Type<T>();
        size = sizeof(data);
    }
    ~node() {}
    void *Data() {
        return &data;

    }
};

// template specialization just for "char *" strings
template <> struct node<const char*> : public nodeBase // this is a template specialization just for strings
{
    char *data;
    node(const char *_data)
    {
        type = Type<const char*>();
        size = strlen(_data) + 1;
        data = new char[size];
        strcpy_s(data, size, _data);
    }
    ~node() { delete data; }
    void *Data() { return data; }
};

// create function makes node<T> and returns base class pointer
template <typename T> nodeBase *create(T data) { return new node<T>(data); }

template specialization of "create" function to pack in std::strings as just "char *" strings
template <> nodeBase *create<std::string>(std::string data) { return create(data.c_str()); }

// this function needs to expand according to what types you want to retrieve
void displayNode(nodeBase *n)
{
    if (!n) return;

    std::cout << n->type << "( " << n->size << " bytes ) ";

    if (n->type == Type<float>())
    {
        std::cout << " = " << *(float *)(n->Data()) << std::endl;
    }
    else if (n->type == Type<double>())
    {
        std::cout << " = " << *(double *)(n->Data()) << std::endl;
    }
    else if (n->type == Type<char const *>())
    {
        std::cout << " = " << (const char *)n->Data() << std::endl;
    }
    else
    {
        std::cout << " = " << *(int *)n->Data() << std::endl;
    }
}

// really simple stack implementation for storing a list
class stack
{
public:
    nodeBase *head = nullptr;
    unsigned int count;

    ~stack()
    {
        while (head)
        {
            nodeBase *temp = head;
            head = head->next;
            delete temp;
        }
    }

    // custom templated push function
    template <typename T> void push(T data)
    {
        nodeBase *new_node = create(data);
        new_node->next = head;
        head = new_node;
        count++;
    }

    // quick and dirty [] operator to access the values for the print test
    nodeBase *operator[](int index)
    {
        nodeBase *node = head;

        while (index > 0 && node != nullptr)
        {
            node = node->next;
            index--;
        }

        return node;
    }
};

struct Cat { int whiskers = 1000; };

int test_list_multi()
{
    stack list1;

    // pushes a bunch of junk into the list to show it really can store just about anything without needing obtuse syntax
    list1.push(44);
    list1.push(2.0423423432f);
    list1.push("drugs");
    list1.push(std::string("hello"));
    list1.push(bool(true));
    list1.push(2.4545);
    list1.push('a');
    list1.push(short(66));
    list1.push([] { int a, b; });
    list1.push([] { int a; });
    struct Dog { int legs[4]{ 9,9,9,9 }; char tail{ 't' }; };
    Dog dog;
    Cat cat;
    list1.push(dog);
    list1.push(cat);

    std::cout << "count = " << list1.count << std::endl;

    // go through the list and display details for each node including type and value
    for (int i = 0; i < list1.count; ++i)
    {
        displayNode(list1[i]);
    }

    std::cin.ignore();
    std::cin.get();
    return 0;
}
Jason Lang
  • 1,079
  • 9
  • 17