2016-07-07 3 views
0

В этом видео я нашел следующий код, и мне очень понравилось.Определение пользовательских типов в шаблоне метапрограммирования

#include <iostream> 

using namespace std; 

#define LIST1(T1) Node<T1,Null> 
#define LIST2(T1,T2) Node<T1,LIST1(T2)> 
#define LIST3(T1,T2,T3) Node<T1,LIST2(T2,T3)> 
#define LIST4(T1,T2,T3,T4) Node<T1,LIST3(T2,T3,T4)> 

struct Null { }; 
template <int X, typename Next> 
struct Node { 
    static const int val = X; 
    typedef Next Next_; 
}; 

template <typename List> 
struct Sum 
{ 
    static const int sum = List::val + Sum<typename List::Next_>::sum; 
}; 

template <> 
struct Sum<Null> { 
    static const int sum = 0; 
}; 

int main() 
{ 
    cout << Sum<LIST4(2, 2, 3, 4)>::sum << endl; 
} 

Мой вопрос в том, что это лучший способ сделать это? Какими другими способами я должен заниматься подобным разбором? Основная проблема, которую я вижу, - это директива препроцессора, используемая для определения типа. Есть ли другой способ сделать это?

Например, я хочу представлять IP-адрес такой же, как указано выше:

Sum<IP<120.100.10.20>> 

, который будет анализировать входной сигнал.

Также, если это возможно взять из файла, было бы гораздо полезнее. Я думаю, что такие форматированные данные должны быть разрешены к типу в TMP. Как мне изменить код для поддержки этого?

Редактировать :: Добавление другого кода, который заставляет меня чувствовать, что это будет полезно.

#include <iostream> 
#define LIST1(T1) Node<T1,Null> 
#define LIST2(T1,T2) Node<T1,LIST1(T2)> 
#define LIST3(T1,T2,T3) Node<T1,LIST2(T2,T3)> 
#define LIST4(T1,T2,T3,T4) Node<T1,LIST3(T2,T3,T4)> 

using namespace std; 

// Highest bit in an IP address 
template <typename List, int N, bool B> 
struct highestBitSet 
{ 
    static const bool b = List::val & (1 << N); 
    static const int bit = highestBitSet<List, N - 1, b>::bit; 
}; 

template <typename List, int N> 
struct highestBitSet<List,N,true> 
{ 
    static const int bit = N+1; 
}; 

template <typename List> 
struct highestBitSet<List, -1, false> 
{ 
    static const int bit = 8+highestBitSet<List::Next_, 7, false>::bit; 
}; 

template <int X> 
struct highestBitSet<Null, X, false> 
{ 
    static const int bit = 0; 
}; 


int main() 
{ 
    // Will print 0 
    cout << highestBitSet<LIST4(1, 0, 0, 0), 7, false>::bit << endl; 
    // WIll print 31 
    cout << highestBitSet<LIST4(0, 0, 0, 255), 7, false>::bit << endl; 
    return 0; 
} 
+2

Это похоже на решение для бедного человека (C++ 98 bound) для переменных параметров шаблонов шаблонов. Добро пожаловать в текущее десятилетие. –

+0

@ πάνταῥεῖ Действительно, это похоже на то, что делает Андрей Александреску в своей книге Modern C++ Design для списков типов. – user2296177

+0

@ πάνταῥεῖ Извините, я не очень хорошо знаком со старой мыслью и новыми реализациями. Можете ли вы направить меня? –

ответ

3

Мой вопрос, что это лучший способ сделать это? Какими другими способами я должен заниматься подобным разбором? Основная проблема, которую я вижу, - это директива препроцессора, используемая для определения типа. Есть ли другой способ сделать это?

Используя кратные выражения 17 C++, либо 14 constexpr, если C++ 17 не доступен C++:

#include <iostream> 

template<int... N> int_list { }; 

template<int... N> int_list<N...> list() { return {}; } 

template<int... N> 
int sum(int_list<N...>) 
{ 
#if __cplusplus > 201402L 
    return (N + ...); 
#else 
    const int vals[] = { N... }; 
    int sum = 0; 
    for (auto v : vals) 
    sum += v; 
    return sum; 
#endif 
} 

int main() 
{ 
    std::cout << sum(list<2, 2, 3, 4>()) << std::endl; 
} 

Например, я хочу представлять IP-адрес так же, как описано выше:

Sum<IP<120.100.10.20>> 

который проанализирует ввод.

Вам не нужен список переменной длины для IPv4-адреса, он всегда имеет четыре компонента. И код, который вы показали, не выполняет никакого разбора ... это будет совершенно другая проблема. Передача четырех отдельных аргументов макросу или функции типа LIST4(120, 100, 10, 20) полностью отличается от записи 120.100.10.20, которая даже не является допустимым токеном C++.

Кроме того, если это можно взять из файла, это было бы гораздо более полезно. Я думаю, что такие форматированные данные должны быть разрешены к типу в TMP. Как мне изменить код для поддержки этого?

Чтение данных из файла - это эффект времени выполнения, вы не можете комбинировать шаблоны (время компиляции) с I/O (время выполнения).

+0

Это действительно интересно. Можете ли вы также сообщить мне, можно ли загрузить из файла значения списка. Как и у меня есть список IP-адресов в файле, я хочу использовать их для отправки в TMP. Является ли это возможным? –

+0

Я уже ответил, что. –

+0

спасибо Джонатан, конечно, вы сделали –