Шаблонный оператор for для перечисления типов.

Николай Бахтин
Николай Бахтин

Хотелось бы иметь возможность перечислять в цикле типы, подобно тому как можно обрабатывать в существующем цикле значения.

 

Предположим у нас есть «нечто» – контейнер типов в виде списка.

typelist MyTypeList
{
  int,
 
double,
 
std::vector<int>
};

Напишем код перечисления типов в списке.

template<typename T>
for( T : MyTypeList)
{
  std::cout << typeid(T).name() << " - size=" << sizeof(T) << std::endl;
}

По сути этот цикл является шаблоном, который в коде разворачивается в последовательность блоков для каждого типа:

//int
{
  std::cout << typeid(int).name() << " - size=" << sizeof(int) << std::endl;
}
//double
{
  std::cout << typeid(double).name() << " - size=" << sizeof(double) << std::endl;
}
//std::vector<int>
{
  std::cout << typeid(std::vector<int>).name() << " - size=" << sizeof(std::vector<int>) << std::endl;
}

 

Обобщенно, цикл

template<T>
for ( T : type_range )
{
  loop_statement
}

развертывается в:

loop_statement<T1>;
loop_statement<T2>;
loop_statement<T3>;

loop_statement<Tn>;

где:

T1,T2,T3...Tn перечень типов, входящих в type_range

 

В качестве type_range можно было взять имя структуры или класса, а в качестве перечисляемых сущностей использовать поля. Но поле помимо типа имеет ещё и имя. Получается, это будет не список типов, а некий список пар «имя поля»-«тип поля».

 

Тогда пускай тип T в цикле описывает пару «имя/тип»

 

struct MyStruct
{
  int a;
  double b;
  std::string c;
};

template<typename T>
for( T : MyStruct)
{
  std::cout << " type=" << typeid(T::field_type).name();
 
std::cout << " name=" << T::field_name << std::endl;
}

Такой цикл должен вывести что-то вроде:
type=int name=a
type=double 
name=b
type=std::string name=c

 

Аналогично для классов. Думаю, таким образом можно реализовать некоторое подобие функционала System.Reflection из С# и других языков.

 

Я не силен в фунциональных языках, но мне кажется, что с помощью этой штуки можно реализовать некоторый функционал монад, который нельзя сделать текущими средствами языка с++. (А может я просто не понимаю, что такое монады. :)

 

Тут я привел скорее общую идею, чем конкретную реализацию. Что думаете об этой идее?

0
рейтинг
5 комментариев
maxon

Первого уже сейчас можно добиться с помощью концептов:

template<typename T>
concept Types = 
	std::is_same_v<T, int> || 
	std::is_same_v<T, double> || 
	std::is_same_v<T, std::vector<int>>;
 
 template<typename T> requires Types<T>
 void f(T t) 
 {
 	std::cout << typeid(T).name() << " - size=" << sizeof(T) << std::endl;
 }

, причём гибче чем в Вашем предложении: например, вместо std::is_same можно так же использовать std::is_convertible. Ну или любые другие type_traits.

Второй пример -- это, по сути, часть Reflection TS, принятия которго с нетерпением ждём.

maxon
Обновлено 
Николай Бахтин

Кхм, может я чего-то не понимаю, я не настолько хорошо знаком с концептами, но в данном примере накладывается ограничение на тип T, либо int, либо double, либо std::vector<int>.

Как это связано с тем, что я говорил, мне непонятно. :(

Николай Бахтин
Николай Бахтин

Мне кажется, что шаблонный оператор for, это довольно простая для понимания конструкция, сильно не нагружающая код (в плане зрительного восприятия), но позволяющая делать вещи, которые ранее было делать нельзя, или затруднительно.

На мой субъективный взгляд конструкция вида:

template<T>
for ( T : type_range )
{
  loop_statement
}

легко воспринимается глазами. Тут много знакомого от обычного с++.

Николай Бахтин
Николай Фоменко

Первая часть кода это вариативный шаблон:

 

#include <iostream>
#include <vector>

template<typename... U>
struct Foo
{
    static void print();
};


template<typename T, typename... U>
struct Foo<T,U...>
{
    static void print()
    {
        std::cout << typeid(T).name() << " - size=" << sizeof(T) << std::endl;
        Foo<U...>::print();
    }
};

template<>
struct Foo<>
{
    static void print() {}
};

int main()
{
    Foo<int,double,std::vector<int>>::print();
    return 0;
}
Николай Фоменко
Andrey

http://wg21.link/P1306

Andrey
Другие идеи
Группа создана, чтобы собирать предложения к стандарту C++, организовывать их внутренние обсуждения, помогать готовить их для отправки в комитет и защищать на общих собраниях в рабочей группе по С++ Международной организации по стандартизации (ISO).
Все предложения