简体   繁体   中英

C++ Counting types without using stateful metaprogramming

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?

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM