2

I was trying to see if I can make a heterogeneous type that can only contain one of several types in its lifetime(an either pattern), and I want to do this:

//strong typed (heterogeneous) container
template<typename list>
struct STC
{
    template<typename a>
    STC(const a& value) :hc_(value), index_(TMP::elem_index<a, list>::value) {}

    template<typename a>
    STC(a&& value) : hc_(value), index_(TMP::elem_index<a, list>::value) {}

    //imaginary compile time const
    constexpr size_t index()const { return index_; }

    typename TMP::index<list,index()>::type get() { return c_.get<index()>(); } 

    operator typename TMP::index<list,index()>::type ()const { return get(); }

private:
    union_magic<list> c_;
    const size_t index_;
};

where typename list is a template meta type list, TMP::elem_index is a template meta function for retriving the index of an list element, and TMP::index is a meta function for retriving element with known index.

It seems to me that there is no way to cross the line between class data member and compile time constant. Am I missing something? Is this the wrong approach? Or it's just something impossible to do in c++, and has to be resolved in runtime?

As for how do I use the container:

    void call_with(char c)
    {
        std::cout << "calling function with char type: " << c << std::endl;
    }

    void call_with(int i)
    {
        std::cout << "calling function with int type: " << i<< std::endl;
    }

    int main()
    {        
    STC<Cons<int, Cons<char, Nil>>> value(1);
    call_with(value);
    }

should display "calling function with int type: 1".

  • 1
    Can you give an example of a compile time application of this class template? i.e., in what way would it be used such that it needs to be compile time? – Brian Bi Jun 18 '18 at 06:48
  • Is `list` a list of type `a` elements, otherwise compile time error? I.e. could you have described `list` as `std::vector`? – Edy Jun 18 '18 at 06:53
  • @Brian For instance, I can provide a template implicit cast operator that only cast to the type it's holding, so when providing with two overloading functions taking both type, this container will only pick the correct one. – Yunsheng Guo Jun 18 '18 at 06:54
  • @Edy list is a list of type in the form of cons>. – Yunsheng Guo Jun 18 '18 at 06:55
  • 1
    Can you show a code snippet? It would really help make the question clearer. – Brian Bi Jun 18 '18 at 06:56
  • @Brian This is the code snippet I'm trying to make work. What other snippets would you like to see? An implementation of union_magic? More on template meta type list? Or what would I like to do with fictional member wise compile-time const(the use of either type)? – Yunsheng Guo Jun 18 '18 at 07:00
  • what is `TMP`? what is the problem with making field like `size_t value{compile_time_constant};`? – user7860670 Jun 18 '18 at 07:03
  • 1
    I'd like to see how you would *use* the compile time constant you want to store inside `STC`. – Brian Bi Jun 18 '18 at 07:06
  • @VTT As you can see, the value is initialized with the instance, and it remains const during its lifetime. I'd love to tell the type in compile time, and I'm wondering how do I keep the compile-time constant `elem_index::value`. `TMP` stands for template metaprogramming. Think of it as juggling types around like data but in compile time. – Yunsheng Guo Jun 18 '18 at 07:09
  • So what is the exact problem with storing `elem_index::value` in the class field? You should post some usage code demonstrating behavior that is not working properly right now. – user7860670 Jun 18 '18 at 07:13
  • @Brian I've updated the question with an example. – Yunsheng Guo Jun 18 '18 at 07:23
  • @VTT I've updated the question with an example. The problem with storing const in the class field is that it's a runtime const, I can't use it as a template parameter. I know there are runtime resolving solutions, and I'm just trying stuff out, see how far I can go with TMP. – Yunsheng Guo Jun 18 '18 at 07:25
  • 1
    Your example is impossible. All objects of type `STC>>` will result in the same overload being called. Overload resolution only considers types. – Brian Bi Jun 18 '18 at 07:25
  • @Brian what about the get method? If I can store a **compile-time** const in the instance, it seems it will work. Otherwise, I guess it's impossible to store one in a class instance. – Yunsheng Guo Jun 18 '18 at 07:29
  • If the type is known at compile time, just use different types, either directly or via a nested type alias. If the type is not known at compile time, well, then you can't know the type at compile time. – aschepler Jun 18 '18 at 15:56

1 Answers1

1

Would the combination of the two following answers help to get what you want?

building and accessing a list of types at compile time

How can I get the index of a type in a variadic class template?

BTW, it's not useful to store a compile-time metatype in index_, which is allocated and can only be used at run time. You'd probably define it as a static constexpr size_t kIndex instead.

Edy
  • 462
  • 3
  • 9
  • But then it's not an instance field anymore, and in order to initialize the static constexpr, I have to include the value in its type name which is something I'm trying to avoid. There is no point to pursue a more complicated type if runtime can do the job, I guess I'm asking is there a way to do more without a complicated type in compile time. Btw I'm good with compile-time lists, since I'm familiar with Haskell. – Yunsheng Guo Jun 18 '18 at 07:35
  • Do you mind elaborate a little bit more on compile-time/runtime allocation so that I can make your answer the accepted one? – Yunsheng Guo Jun 18 '18 at 17:13
  • @YunshengGuo `const size_t index_;` declares a data member for every instance of `struct STC`. It is allocated and initialized at run time. You wouldn't be able to "use" it as a compile-time argument (I previously misspoke -- you *can* store compile-time constant in it; but only could *use* it at run time). What this means is that instead of doing `constexpr size_t index()const { return index_; }`, it may be more straightforward to do something like `static constexpr size_t kIndex = TMP::elem_index::value`? – Edy Jun 19 '18 at 06:42
  • That was my intent to use instance because I want static polymorphic behavior without static cast, and I now start to realize it's not possible in c++. – Yunsheng Guo Jun 20 '18 at 04:48