2

I'm trying to incrementally create a list of types by registering the types with a macro. To do so I want to use a trick I found into an answer to another question. The reduced code is the following:

#include <iostream>
#include <type_traits>
#include <utility>
#include <tuple>

#define MAXIMUM_SIZE 100

template <std::size_t N>
struct Index : Index<N - 1> {};
template <>
struct Index<0> {};

std::tuple<> GetTypes(Index<0>) { return {}; }

#define GET_REGISTERED_TYPES \
  decltype(GetTypes(std::declval<Index<MAXIMUM_SIZE>>()))

#define REGISTER_TYPE(Type)                              \
    inline decltype(std::tuple_cat( \
        std::declval<GET_REGISTERED_TYPES>(), \
        std::declval<std::tuple<Type>>()))        \
  GetTypes(Index<std::tuple_size_v<GET_REGISTERED_TYPES> + 1>) { \
    return {};                                                \
  }
REGISTER_TYPE(int)
REGISTER_TYPE(float)
REGISTER_TYPE(char)
REGISTER_TYPE(Index<78>)
int main() {
    // true
    std::cout << std::boolalpha 
        << std::is_same_v<
            GET_REGISTERED_TYPES,
            std::tuple<int, float, char, Index<78>>> 
        << std::endl;
}

Is this kind of code considered safe to use or it is part of some obscure parts of the language and shoulnd't be used for production. Also I don't get the issue about statefull metaprogramming that a comment argued. The only thing that REGISTER_TYPE macro does is declaring a NEW function overload. How can this be considered state modification?

In order for this trick to stop working, some foundamental changes to the c++ rules of picking overload function should be introduced with the effect that every medium program out there would stop compiling. Am I correct?

barsdeveloper
  • 930
  • 8
  • 28

1 Answers1

0

Imagine you have two headers:

// foo.h
#ifndef foo_h
#define foo_h
#include "register_type.h"    
REGISTER_TYPE(int)
#endif

and

// bar.h
#ifndef bar_h
#define bar_h
#include "register_type.h"    
REGISTER_TYPE(double)
#endif

Then this two sources will have different definitions of GetTypes(std::declval<Index<MAXIMUM_SIZE>>()):

// a.cpp
#include "foo.h"
#include "bar.h"

inline void test() {
    std::cout << std::boolalpha 
        << std::is_same_v<
            GET_REGISTERED_TYPES,
            std::tuple<int, double>       // true
    << std::endl;
}

// b.cpp
#include "bar.h"     // <--- different order of includes
#include "foo.h"

inline void test() {
    std::cout << std::boolalpha 
        << std::is_same_v<
            GET_REGISTERED_TYPES,
            std::tuple<int, double>       // false !!
    << std::endl;
}
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • That's not really an answer. You can compare the tuples in an unordered fashion. As for the single definition rule, you can keep your registrations in a header and include that one. – barsdeveloper Feb 08 '20 at 12:46
  • @barsan-md but you shall not have two different definitions. I was going to back it up with more information but still reading... – 463035818_is_not_an_ai Feb 08 '20 at 12:48
  • @barsan-md well, I cannot know what the commenter thought is wrong with the approach. I showed you one way it can break terribly, saying that it can be used in a right way is no real counterargument – 463035818_is_not_an_ai Feb 08 '20 at 12:50
  • Ok I see your point. If the alternative is to declare the list manually then you will not encounter this problem because it's definition cannot be physically split across multiple headers (at least without making that obvious). Fair point but that was not the worry I asked opinions about. Thanks for taking time answering though! – barsdeveloper Feb 08 '20 at 13:06
  • 1
    @barsan-md ok now I see your point ;). You want to know if your code as written is well defined. I do not see the problem, but I am not certain enough to count on that. Btw once you realized that you have to put all `REGISTER_TYPE(xyz)` in one single header I do not see the advantage comared to to putting `using registered_types = std::tuple;` in that header instead of the macros – 463035818_is_not_an_ai Feb 08 '20 at 14:38