C++ templates Turing-complete? - c++

I'm told that the template system in C++ is Turing-complete at compile time. This is mentioned in this post and also on wikipedia.
Can you provide a nontrivial example of a computation that exploits this property?
Is this fact useful in practice?

I've done a turing machine in C++11. Features that C++11 adds are not significant for the turing machine indeed. It just provides for arbitrary length rule lists using variadic templates, instead of using perverse macro metaprogramming :). The names for the conditions are used to output a diagram on stdout. i've removed that code to keep the sample short.
#include <iostream>
template<bool C, typename A, typename B>
struct Conditional {
typedef A type;
};
template<typename A, typename B>
struct Conditional<false, A, B> {
typedef B type;
};
template<typename...>
struct ParameterPack;
template<bool C, typename = void>
struct EnableIf { };
template<typename Type>
struct EnableIf<true, Type> {
typedef Type type;
};
template<typename T>
struct Identity {
typedef T type;
};
// define a type list
template<typename...>
struct TypeList;
template<typename T, typename... TT>
struct TypeList<T, TT...> {
typedef T type;
typedef TypeList<TT...> tail;
};
template<>
struct TypeList<> {
};
template<typename List>
struct GetSize;
template<typename... Items>
struct GetSize<TypeList<Items...>> {
enum { value = sizeof...(Items) };
};
template<typename... T>
struct ConcatList;
template<typename... First, typename... Second, typename... Tail>
struct ConcatList<TypeList<First...>, TypeList<Second...>, Tail...> {
typedef typename ConcatList<TypeList<First..., Second...>,
Tail...>::type type;
};
template<typename T>
struct ConcatList<T> {
typedef T type;
};
template<typename NewItem, typename List>
struct AppendItem;
template<typename NewItem, typename...Items>
struct AppendItem<NewItem, TypeList<Items...>> {
typedef TypeList<Items..., NewItem> type;
};
template<typename NewItem, typename List>
struct PrependItem;
template<typename NewItem, typename...Items>
struct PrependItem<NewItem, TypeList<Items...>> {
typedef TypeList<NewItem, Items...> type;
};
template<typename List, int N, typename = void>
struct GetItem {
static_assert(N > 0, "index cannot be negative");
static_assert(GetSize<List>::value > 0, "index too high");
typedef typename GetItem<typename List::tail, N-1>::type type;
};
template<typename List>
struct GetItem<List, 0> {
static_assert(GetSize<List>::value > 0, "index too high");
typedef typename List::type type;
};
template<typename List, template<typename, typename...> class Matcher, typename... Keys>
struct FindItem {
static_assert(GetSize<List>::value > 0, "Could not match any item.");
typedef typename List::type current_type;
typedef typename Conditional<Matcher<current_type, Keys...>::value,
Identity<current_type>, // found!
FindItem<typename List::tail, Matcher, Keys...>>
::type::type type;
};
template<typename List, int I, typename NewItem>
struct ReplaceItem {
static_assert(I > 0, "index cannot be negative");
static_assert(GetSize<List>::value > 0, "index too high");
typedef typename PrependItem<typename List::type,
typename ReplaceItem<typename List::tail, I-1,
NewItem>::type>
::type type;
};
template<typename NewItem, typename Type, typename... T>
struct ReplaceItem<TypeList<Type, T...>, 0, NewItem> {
typedef TypeList<NewItem, T...> type;
};
enum Direction {
Left = -1,
Right = 1
};
template<typename OldState, typename Input, typename NewState,
typename Output, Direction Move>
struct Rule {
typedef OldState old_state;
typedef Input input;
typedef NewState new_state;
typedef Output output;
static Direction const direction = Move;
};
template<typename A, typename B>
struct IsSame {
enum { value = false };
};
template<typename A>
struct IsSame<A, A> {
enum { value = true };
};
template<typename Input, typename State, int Position>
struct Configuration {
typedef Input input;
typedef State state;
enum { position = Position };
};
template<int A, int B>
struct Max {
enum { value = A > B ? A : B };
};
template<int n>
struct State {
enum { value = n };
static char const * name;
};
template<int n>
char const* State<n>::name = "unnamed";
struct QAccept {
enum { value = -1 };
static char const* name;
};
struct QReject {
enum { value = -2 };
static char const* name;
};
#define DEF_STATE(ID, NAME) \
typedef State<ID> NAME ; \
NAME :: name = #NAME ;
template<int n>
struct Input {
enum { value = n };
static char const * name;
template<int... I>
struct Generate {
typedef TypeList<Input<I>...> type;
};
};
template<int n>
char const* Input<n>::name = "unnamed";
typedef Input<-1> InputBlank;
#define DEF_INPUT(ID, NAME) \
typedef Input<ID> NAME ; \
NAME :: name = #NAME ;
template<typename Config, typename Transitions, typename = void>
struct Controller {
typedef Config config;
enum { position = config::position };
typedef typename Conditional<
static_cast<int>(GetSize<typename config::input>::value)
<= static_cast<int>(position),
AppendItem<InputBlank, typename config::input>,
Identity<typename config::input>>::type::type input;
typedef typename config::state state;
typedef typename GetItem<input, position>::type cell;
template<typename Item, typename State, typename Cell>
struct Matcher {
typedef typename Item::old_state checking_state;
typedef typename Item::input checking_input;
enum { value = IsSame<State, checking_state>::value &&
IsSame<Cell, checking_input>::value
};
};
typedef typename FindItem<Transitions, Matcher, state, cell>::type rule;
typedef typename ReplaceItem<input, position, typename rule::output>::type new_input;
typedef typename rule::new_state new_state;
typedef Configuration<new_input,
new_state,
Max<position + rule::direction, 0>::value> new_config;
typedef Controller<new_config, Transitions> next_step;
typedef typename next_step::end_config end_config;
typedef typename next_step::end_input end_input;
typedef typename next_step::end_state end_state;
enum { end_position = next_step::position };
};
template<typename Input, typename State, int Position, typename Transitions>
struct Controller<Configuration<Input, State, Position>, Transitions,
typename EnableIf<IsSame<State, QAccept>::value ||
IsSame<State, QReject>::value>::type> {
typedef Configuration<Input, State, Position> config;
enum { position = config::position };
typedef typename Conditional<
static_cast<int>(GetSize<typename config::input>::value)
<= static_cast<int>(position),
AppendItem<InputBlank, typename config::input>,
Identity<typename config::input>>::type::type input;
typedef typename config::state state;
typedef config end_config;
typedef input end_input;
typedef state end_state;
enum { end_position = position };
};
template<typename Input, typename Transitions, typename StartState>
struct TuringMachine {
typedef Input input;
typedef Transitions transitions;
typedef StartState start_state;
typedef Controller<Configuration<Input, StartState, 0>, Transitions> controller;
typedef typename controller::end_config end_config;
typedef typename controller::end_input end_input;
typedef typename controller::end_state end_state;
enum { end_position = controller::end_position };
};
#include <ostream>
template<>
char const* Input<-1>::name = "_";
char const* QAccept::name = "qaccept";
char const* QReject::name = "qreject";
int main() {
DEF_INPUT(1, x);
DEF_INPUT(2, x_mark);
DEF_INPUT(3, split);
DEF_STATE(0, start);
DEF_STATE(1, find_blank);
DEF_STATE(2, go_back);
/* syntax: State, Input, NewState, Output, Move */
typedef TypeList<
Rule<start, x, find_blank, x_mark, Right>,
Rule<find_blank, x, find_blank, x, Right>,
Rule<find_blank, split, find_blank, split, Right>,
Rule<find_blank, InputBlank, go_back, x, Left>,
Rule<go_back, x, go_back, x, Left>,
Rule<go_back, split, go_back, split, Left>,
Rule<go_back, x_mark, start, x, Right>,
Rule<start, split, QAccept, split, Left>> rules;
/* syntax: initial input, rules, start state */
typedef TuringMachine<TypeList<x, x, x, x, split>, rules, start> double_it;
static_assert(IsSame<double_it::end_input,
TypeList<x, x, x, x, split, x, x, x, x>>::value,
"Hmm... This is borky!");
}

Example
#include <iostream>
template <int N> struct Factorial
{
enum { val = Factorial<N-1>::val * N };
};
template<>
struct Factorial<0>
{
enum { val = 1 };
};
int main()
{
// Note this value is generated at compile time.
// Also note that most compilers have a limit on the depth of the recursion available.
std::cout << Factorial<4>::val << "\n";
}
That was a little fun but not very practical.
To answer the second part of the question:
Is this fact useful in practice?
Short Answer: Sort of.
Long Answer: Yes, but only if you are a template daemon.
To turn out good programming using template meta-programming that is really useful for others to use (ie a library) is really really tough (though do-able). To Help boost even has MPL aka (Meta Programming Library). But try debugging a compiler error in your template code and you will be in for a long hard ride.
But a good practical example of it being used for something useful:
Scott Meyers has been working extensions to the C++ language (I use the term loosely) using the templating facilities. You can read about his work here 'Enforcing Code Features'

"C++ Templates Are Turing Complete" gives an implementation of a Turing machine in templates ... which is non-trivial and proves the point in a very direct way. Of course, it also isn't very useful!

My C++ is a bit rusty, so the may not be perfect, but it's close.
template <int N> struct Factorial
{
enum { val = Factorial<N-1>::val * N };
};
template <> struct Factorial<0>
{
enum { val = 1 };
}
const int num = Factorial<10>::val; // num set to 10! at compile time.
The point is to demonstrate that the compiler is completely evaluating the recursive definition until it reaches an answer.

To give a non-trivial example: https://github.com/phresnel/metatrace , a C++ compile time ray tracer.
Note that C++0x will add a non-template, compile-time, turing-complete facility in form of constexpr:
constexpr unsigned int fac (unsigned int u) {
return (u<=1) ? (1) : (u*fac(u-1));
}
You can use constexpr-expression everywhere where you need compile time constants, but you can also call constexpr-functions with non-const parameters.
One cool thing is that this will finally enable compile time floating point math, though the standard explicitly states that compile time floating point arithmetics do not have to match runtime floating point arithmetics:
bool f(){
char array[1+int(1+0.2-0.1-0.1)]; //Must be evaluated during translation
int size=1+int(1+0.2-0.1-0.1); //May be evaluated at runtime
return sizeof(array)==size;
}
It is unspeciļ¬ed whether the value of f() will be true or false.

The factorial example actually does not show that templates are Turing complete, as much as it shows that they support Primitive Recursion. The easiest way to show that templates are turing complete is by the Church-Turing thesis, that is by implementing either a Turing machine (messy and a bit pointless) or the three rules (app, abs var) of the untyped lambda calculus. The latter is much simpler and far more interesting.
What is being discussed is an extremely useful feature when you understand that C++ templates allow pure functional programming at compile time, a formalism that is expressive, powerful and elegant but also very complicated to write if you have little experience. Also notice how many people find that just getting heavily templatized code can often require a big effort: this is exactly the case with (pure) functional languages, which make compiling harder but surprisingly yield code that does not require debugging.

The Book Modern C++ Design - Generic Programming and Design Pattern by Andrei Alexandrescu is the best place to get hands on experience with useful and powerful generic programing patterns.

I think it's called template meta-programming.

Well, here's a compile time Turing Machine implementation running a 4-state 2-symbol busy beaver
#include <iostream>
#pragma mark - Tape
constexpr int Blank = -1;
template<int... xs>
class Tape {
public:
using type = Tape<xs...>;
constexpr static int length = sizeof...(xs);
};
#pragma mark - Print
template<class T>
void print(T);
template<>
void print(Tape<>) {
std::cout << std::endl;
}
template<int x, int... xs>
void print(Tape<x, xs...>) {
if (x == Blank) {
std::cout << "_ ";
} else {
std::cout << x << " ";
}
print(Tape<xs...>());
}
#pragma mark - Concatenate
template<class, class>
class Concatenate;
template<int... xs, int... ys>
class Concatenate<Tape<xs...>, Tape<ys...>> {
public:
using type = Tape<xs..., ys...>;
};
#pragma mark - Invert
template<class>
class Invert;
template<>
class Invert<Tape<>> {
public:
using type = Tape<>;
};
template<int x, int... xs>
class Invert<Tape<x, xs...>> {
public:
using type = typename Concatenate<
typename Invert<Tape<xs...>>::type,
Tape<x>
>::type;
};
#pragma mark - Read
template<int, class>
class Read;
template<int n, int x, int... xs>
class Read<n, Tape<x, xs...>> {
public:
using type = typename std::conditional<
(n == 0),
std::integral_constant<int, x>,
Read<n - 1, Tape<xs...>>
>::type::type;
};
#pragma mark - N first and N last
template<int, class>
class NLast;
template<int n, int x, int... xs>
class NLast<n, Tape<x, xs...>> {
public:
using type = typename std::conditional<
(n == sizeof...(xs)),
Tape<xs...>,
NLast<n, Tape<xs...>>
>::type::type;
};
template<int, class>
class NFirst;
template<int n, int... xs>
class NFirst<n, Tape<xs...>> {
public:
using type = typename Invert<
typename NLast<
n, typename Invert<Tape<xs...>>::type
>::type
>::type;
};
#pragma mark - Write
template<int, int, class>
class Write;
template<int pos, int x, int... xs>
class Write<pos, x, Tape<xs...>> {
public:
using type = typename Concatenate<
typename Concatenate<
typename NFirst<pos, Tape<xs...>>::type,
Tape<x>
>::type,
typename NLast<(sizeof...(xs) - pos - 1), Tape<xs...>>::type
>::type;
};
#pragma mark - Move
template<int, class>
class Hold;
template<int pos, int... xs>
class Hold<pos, Tape<xs...>> {
public:
constexpr static int position = pos;
using tape = Tape<xs...>;
};
template<int, class>
class Left;
template<int pos, int... xs>
class Left<pos, Tape<xs...>> {
public:
constexpr static int position = typename std::conditional<
(pos > 0),
std::integral_constant<int, pos - 1>,
std::integral_constant<int, 0>
>::type();
using tape = typename std::conditional<
(pos > 0),
Tape<xs...>,
Tape<Blank, xs...>
>::type;
};
template<int, class>
class Right;
template<int pos, int... xs>
class Right<pos, Tape<xs...>> {
public:
constexpr static int position = pos + 1;
using tape = typename std::conditional<
(pos < sizeof...(xs) - 1),
Tape<xs...>,
Tape<xs..., Blank>
>::type;
};
#pragma mark - States
template <int>
class Stop {
public:
constexpr static int write = -1;
template<int pos, class tape> using move = Hold<pos, tape>;
template<int x> using next = Stop<x>;
};
#define ADD_STATE(_state_) \
template<int> \
class _state_ { };
#define ADD_RULE(_state_, _read_, _write_, _move_, _next_) \
template<> \
class _state_<_read_> { \
public: \
constexpr static int write = _write_; \
template<int pos, class tape> using move = _move_<pos, tape>; \
template<int x> using next = _next_<x>; \
};
#pragma mark - Machine
template<template<int> class, int, class>
class Machine;
template<template<int> class State, int pos, int... xs>
class Machine<State, pos, Tape<xs...>> {
constexpr static int symbol = typename Read<pos, Tape<xs...>>::type();
using state = State<symbol>;
template<int x>
using nextState = typename State<symbol>::template next<x>;
using modifiedTape = typename Write<pos, state::write, Tape<xs...>>::type;
using move = typename state::template move<pos, modifiedTape>;
constexpr static int nextPos = move::position;
using nextTape = typename move::tape;
public:
using step = Machine<nextState, nextPos, nextTape>;
};
#pragma mark - Run
template<class>
class Run;
template<template<int> class State, int pos, int... xs>
class Run<Machine<State, pos, Tape<xs...>>> {
using step = typename Machine<State, pos, Tape<xs...>>::step;
public:
using type = typename std::conditional<
std::is_same<State<0>, Stop<0>>::value,
Tape<xs...>,
Run<step>
>::type::type;
};
ADD_STATE(A);
ADD_STATE(B);
ADD_STATE(C);
ADD_STATE(D);
ADD_RULE(A, Blank, 1, Right, B);
ADD_RULE(A, 1, 1, Left, B);
ADD_RULE(B, Blank, 1, Left, A);
ADD_RULE(B, 1, Blank, Left, C);
ADD_RULE(C, Blank, 1, Right, Stop);
ADD_RULE(C, 1, 1, Left, D);
ADD_RULE(D, Blank, 1, Right, D);
ADD_RULE(D, 1, Blank, Right, A);
using tape = Tape<Blank>;
using machine = Machine<A, 0, tape>;
using result = Run<machine>::type;
int main() {
print(result());
return 0;
}
Ideone proof run: https://ideone.com/MvBU3Z
Explanation: http://victorkomarov.blogspot.ru/2016/03/compile-time-turing-machine.html
Github with more examples: https://github.com/fnz/CTTM

You can check this article from Dr. Dobbs on a FFT implementation with templates which I think not that trivial.
The main point is to allow the compiler to perform a better optimization than for non template implementations as the FFT algorithm uses a lot of constants ( sin tables for instance )
part I
part II

It's also fun to point out that it is a purely functional language albeit nearly impossible to debug. If you look at James post you will see what I mean by it being functional. In general it's not the most useful feature of C++. It wasn't designed to do this. It's something that was discovered.

It may be useful if you want to compute constants at compile time, at least in theory. Check out template metaprogramming.

An example which is reasonably useful is a ratio class. There are a few variants floating around. Catching the D==0 case is fairly simple with partial overloads. The real computing is in calculating the GCD of N and D and compile time. This is essential when you're using these ratios in compile-time calculations.
Example: When you're calculating centimeters(5)*kilometers(5), at compile time you'll be multiplying ratio<1,100> and ratio<1000,1>. To prevent overflow, you want a ratio<10,1> instead of a ratio<1000,100>.

A Turing machine is Turing-complete, but that doesn't mean you should want to use one for production code.
Trying to do anything non-trivial with templates is in my experience messy, ugly and pointless. You have no way to "debug" your "code", compile-time error messages will be cryptic and usually in the most unlikely places, and you can achieve the same performance benefits in different ways. (Hint: 4! = 24). Worse, your code is incomprehensible to the average C++ programmer, and will be likely be non-portable due to wide ranging levels of support within current compilers.
Templates are great for generic code generation (container classes, class wrappers, mix-ins), but no - in my opinion the Turing Completeness of templates is NOT USEFUL in practice.

Just another example of how not to program :
template<int Depth, int A, typename B>
struct K17 {
static const int x =
K17 <Depth+1, 0, K17<Depth,A,B> >::x
+ K17 <Depth+1, 1, K17<Depth,A,B> >::x
+ K17 <Depth+1, 2, K17<Depth,A,B> >::x
+ K17 <Depth+1, 3, K17<Depth,A,B> >::x
+ K17 <Depth+1, 4, K17<Depth,A,B> >::x;
};
template <int A, typename B>
struct K17 <16,A,B> { static const int x = 1; };
static const int z = K17 <0,0,int>::x;
void main(void) { }
Post at C++ templates are turing complete

Related

How to store a type for later comparison

First off my use case, as I may think in the wrong direction: I want to create a map that maps a value to types. So for example:
Map<std::string> map;
map.insert<int, double, char>("Hey");
auto string = map.at<int, double, char>();
This alone is fairly easy to do with std::type_index. However, I want to add the possibility to match types that are not exact the searched ones, when they are convertible. So the following should also return "Hey", as float can be converted to double:
auto string = map.at<int, float, char>();
I can't use type_index for this case as std::is_convertible only works directly on types. This would be the version without conversion, but as far as it seems it's not easily possible to add conversion handling into it without major changes.
My current attempt looks kind of like the following, please note that this is not working and just shows what I have tried to implement:
template<typename T>
class Map {
T value;
std::vector<Map<T>> children; // all the children of the current node.
// in the above example, if this was
// the int node, the only child
// would be the double node
template<typename T1>
constexpr bool is_convertible() const {
return std::is_convertible<__T__, T1>::value; // this isn't applicable
// since __T__ can't be
// stored (this nodes
// type)
}
public:
template<typename T1, typename... Tn>
void insert(T&& value) {
// iterate through/create the child nodes until the last template param
}
template<typename T1, typename... Tn>
T& at() {
// iterate through thechild nodes until a matching child is found
// either exact match or a convertible
for(auto &c: children) {
// if the above function would work
if(c.template is_convertible<T1>()) {
return c.template at<Tn...>();
}
}
}
}
Now I'm at my wits end how to achieve this. I thought of implementing lambdas as comparator functions, but while the lambda can store the type of the current node, it can't accept a template parameter on call to compare to.
Is there some C+1y generic lambda comparator magic, or even an easier way?
I hope this does what you want, there's ample space for extension and for creating template specialization that attach to any type combination you want. It's not super-pretty, but it can probably be refactored a bit and beautified.
#include <iostream>
template <typename... Args>
struct map {
};
template <>
struct map<int, float, char> {
static constexpr char value[] = "int float char";
};
constexpr char map<int,float,char>::value[];
template <typename T>
struct map<int, T> {
static constexpr typename std::enable_if<std::is_integral<T>::value, char>::type value[] = "int, T";
};
template <typename T>
constexpr typename std::enable_if<std::is_integral<T>::value, char>::type map<int,T>::value[];
int main() {
std::string v = map<int,float,char>::value;
std::string w = map<int,int>::value;
std::string w2 = map<int,unsigned>::value;
// std::string w3 = map<int,float>::value; Won't compile
std::cout << v << "\n";
std::cout << w << "\n";
std::cout << w2 << "\n";
return 0;
}
I wrote some weird code using boost::fusion that comes close to doing what you want:
#include <boost/fusion/container/map.hpp>
#include <boost/fusion/include/insert.hpp>
#include <boost/fusion/include/pair.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <string>
#include <iostream>
#include <tuple>
#include <type_traits>
#include <memory>
template <std::size_t Value1, std::size_t Value2>
struct MinSizeT {
static const std::size_t value = (Value1 > Value2) ? Value2 : Value1;
};
template<typename T1, typename T2, std::size_t N>
struct TupleIsConvertibleHelper {
static const bool value = std::is_convertible<typename std::tuple_element<N - 1, T1>::type, typename std::tuple_element<N - 1, T2>::type>::value && TupleIsConvertibleHelper<T1, T2, N - 1>::value;
};
template<typename T1, typename T2>
struct TupleIsConvertibleHelper<T1, T2, 0> {
static const bool value = true;
};
template<typename T1, typename T2>
bool TupleIsConvertible() { // Return true if all types in T1 are convertible to their corresponding type in T2
if (std::tuple_size<T1>::value != std::tuple_size<T2>::value)
return false;
constexpr std::size_t minSize = MinSizeT<std::tuple_size<T1>::value, std::tuple_size<T2>::value>::value;
return TupleIsConvertibleHelper<T1, T2, minSize>::value;
}
template<typename MapInserter>
class Map {
MapInserter mc;
template<typename... Types>
struct do_at {
template <typename T>
void operator()(T const& x) const { // Find an exact match or the last convertible match
typedef std::tuple<Types...> t1;
typedef typename T::first_type t2;
if (exactMatch)
return;
if (std::is_same<t1, t2>::value) {
exactMatch = true;
value = x.second;
}
else if (TupleIsConvertible<t1, t2>())
value = x.second;
}
mutable bool exactMatch;
mutable typename MapInserter::value_type value;
do_at() : exactMatch(false) {}
};
public:
Map(MapInserter _mc) : mc(_mc) { }
template<typename... Types>
typename MapInserter::value_type at() {
do_at<Types...> res;
boost::fusion::for_each(mc.data->map, res);
return res.value;
}
};
template<typename ValueType, typename MapType = boost::fusion::map<>, typename ParentType = void*>
struct MapInserter {
typedef ValueType value_type;
struct Helper {
MapType map;
std::shared_ptr<ParentType> parent; // Must keep parent alive because fusion is lazy.
Helper() = default;
Helper(MapType&& _map, std::shared_ptr<ParentType> _parent) : map(std::move(_map)), parent(_parent) {}
};
std::shared_ptr<Helper> data;
template<typename... KeyTypes>
auto Insert(ValueType value) -> MapInserter<ValueType, decltype(boost::fusion::insert(data->map, boost::fusion::end(data->map), boost::fusion::make_pair<std::tuple<KeyTypes...>>(value))), Helper> {
auto newMap = boost::fusion::insert(data->map, boost::fusion::end(data->map), boost::fusion::make_pair<std::tuple<KeyTypes...>>(value));
return MapInserter<ValueType, decltype(newMap), Helper>(std::move(newMap), data);
}
MapInserter() : data(std::make_shared<Helper>()) { }
MapInserter(MapType&& _map, std::shared_ptr<ParentType> _parent) : data(std::make_shared<Helper>(std::move(_map), _parent)) {}
MapInserter(MapInserter&&) = default;
MapInserter(const MapInserter&) = default;
};
int main() {
auto mc = MapInserter<std::string>().
Insert<int, char, float>("***int, char, float***").
Insert<float, double>("***float, double***").
Insert<int>("***int***").
Insert<unsigned, bool>("***unsigned, bool***");
Map<decltype(mc)> map(mc);
std::cout << map.at<int, char, float>() << std::endl; // "***int, char, float***"
std::cout << map.at<int, char, double>() << std::endl; // "***int, char, float***"
std::cout << map.at<char>() << std::endl; // "***int***"
return 0;
}
template<class...>struct types { typedef types type; };
template<class T, class types>struct type_index;
template<class T, class...Ts>
struct type_index<T,types<T, Ts...>>:
std::integral_constant<unsigned,0>
{};
template<class T, class T0, class...Ts>
struct type_index<T,types<T0, Ts...>>:
std::integral_constant<unsigned,type_index<T,types<Ts...>::value+1>
{};
template<template<class>class filter, class types_in, class types_out=types<>, class details=void>
struct filter;
template<template<class>class filter, class T0, class... Ts, class... Zs>
struct filter<filter, types<T0,types...>, types<Zs...>,
typename std::enable_if< filter<T0>::value >::type
>: filter<filter, types<types...>, types<Zs...,T0>>
{};
template<template<class>class filter, class T0, class... Ts, class... Zs>
struct filter<filter, types<T0,types...>, types<Zs...>,
typename std::enable_if< !filter<T0>::value >::type
>: filter<filter, types<types...>, types<Zs...>>
{};
template<template<class>class filter, class... Zs>
struct filter<filter, types<>, types<Zs...>,
void
>: types<Zs...>
{};
template<typename T>
struct convertable_to_test {
template<typename U>
using test = std::is_convertible<U, T>;
};
template<class T, class types>
struct get_convertable_to_types:filter< convertable_to_test<T>::template test, types> {};
which is a start.
Create a master types<Ts...> of all of the types your system supports. Call this SupportedTypes.
Map types<Ts...> to std::vector<unsigned> of each type offset in the above list. Now you can store a collection of types at runtime. Call this a runtime type vector.
When adding an entry types<Args...> to the map, run get_convertable_to_types on each type in types<Args...>, and build a cross product in types< types<...>... >. Store the resulting exponential number of runtime type vectors in your implementation details map.
When you query with types<Ts...>, conver to the runtime type vector, and look it up in the implementation details map. And done!
An alternative approach would be to write get_convertable_from_types, and do the mapping to an exponential number of types<Ts...> at the query point, convert each to a runtime type vector. When adding stuff to the map, store only one runtime type vector. This has slower lookup performance, but faster setup performance, and uses far less memory.
I was going to finish this, but got busy.

Compile-time quicksort: Passing comparer as template parameter

As part of a personal project, i have developed a template metaprogramming library that has an implemetation of type lists using C++11 variadic templates.
To test typelists operations, such as merge two typelists, split a typelist in two typelists, push_back a type in a typelist, etc (And to do a very freak programming excercise); i have implemented a compile-time version of the quicksort sorting algorithm using template metaprogramming:
NOTE: "dl32" is the prefix of my library types.
#include "dl32MetaprogrammingLibrary.h"
#include <iostream>
using namespace std;
/* quicksort sorts lists of unsigned ints */
template<unsigned int... Ns>
using uint_list = dl32TypeList<dl32UintWrapper<Ns>...>;
using empty_uint_list = dl32EmptyTypeList;
/* set of unsigned int comparers */
template<typename UINT1, typename UINT2>
struct equal : public dl32BoolWrapper< UINT1::value == UINT2::value > {};
template<typename UINT1, typename UINT2>
struct not_equal : public dl32BoolWrapper< UINT1::value != UINT2::value > {};
template<typename UINT1, typename UINT2>
struct bigger_than : public dl32BoolWrapper< (UINT1::value > UINT2::value) > {};
template<typename UINT1, typename UINT2>
struct less_than : public dl32BoolWrapper< (UINT1::value < UINT2::value) > {};
template<typename UINT1, typename UINT2>
struct bigger_or_equal : public dl32BoolWrapper< UINT1::value >= UINT2::value > {};
template<typename UINT1, typename UINT2>
struct less_or_equal : public dl32BoolWrapper< UINT1::value <= UINT2::value > {};
/* Compile-time quicksort implementation */
template<typename UINT_LIST>
class quicksort
{
private:
//Forward declaration:
template<unsigned int lenght , typename SUBLIST>
struct _quicksort;
//Base-case for empty sublists:
template<typename... Ns>
struct _quicksort<0,dl32TypeList<Ns...>>
{
using result = empty_uint_list;
};
//Base case for one element sublists:
template<typename UINT_WRAPPER>
struct _quicksort<1,dl32TypeList<UINT_WRAPPER>>
{
using result = dl32TypeList<UINT_WRAPPER>;
};
//Base-case for two elements sublists (Simple compare and swap):
template<typename FIRST , typename LAST >
struct _quicksort<2,dl32TypeList<FIRST,LAST>>
{
using result = typename dl32tmp_if< bigger_or_equal<FIRST,LAST>::value , //CONDITION
dl32TypeList<FIRST,LAST>, //THEN
dl32TypeList<LAST,FIRST> //ELSE
>::type;
};
//Recursive case:
template<unsigned int lenght , typename... Ns>
struct _quicksort<lenght,dl32TypeList<Ns...>>
{
private:
/* STEP 1: Reorder the sublist in two sublists: Left sublist, with elements greater than pivot, and right, with the others */
//Forward declaration:
template<typename PIVOT , typename RIGHT /* initial (or actual) right sublist */ , typename LEFT /* initial (or actual) left sublist */ , typename _UINT_LIST /* original sublist */>
struct _reorder_sublists;
//Recursive case:
template<typename PIVOT , typename... RIGHT_UINTS , typename... LEFT_UINTS , typename HEAD , typename... TAIL>
struct _reorder_sublists<PIVOT,dl32TypeList<RIGHT_UINTS...>,dl32TypeList<LEFT_UINTS...>,dl32TypeList<HEAD,TAIL...>>
{
using _next_left = dl32TypeList<LEFT_UINTS...,HEAD>; ///< Next left sublist if HEAD is greather than PIVOT.
using _next_right = dl32TypeList<HEAD,RIGHT_UINTS...>; ///< Next right sublist if HEAD is less than PIVOT.
// CONDITION THEN ELSE
using next_left = typename dl32tmp_if< !bigger_or_equal<PIVOT,HEAD>::value , _next_left , dl32TypeList<LEFT_UINTS...>>::type;
using next_right = typename dl32tmp_if< bigger_or_equal<PIVOT,HEAD>::value , _next_right , dl32TypeList<RIGHT_UINTS...>>::type;
using next_reorder = _reorder_sublists<PIVOT,next_right,next_left,dl32TypeList<TAIL...>>; // "Recursive call" (Iteration)
using right = typename next_reorder::right; //Recursive result return
using left = typename next_reorder::left; //Recursive result return
};
//Base case (End of the iteration):
template<typename PIVOT , typename RIGHT , typename LEFT>
struct _reorder_sublists<PIVOT,RIGHT,LEFT,empty_uint_list>
{
using right = RIGHT;
using left = LEFT;
};
template<typename PIVOT>
using _right_sublist = typename _reorder_sublists<PIVOT,empty_uint_list,empty_uint_list,dl32TypeList<Ns...>>::right; //Right sublist computation
template<typename PIVOT>
using _left_sublist = typename _reorder_sublists<PIVOT,empty_uint_list,empty_uint_list,dl32TypeList<Ns...>>::left; //Left sublist computation
private:
static const unsigned int _half_size = lenght/2;
static const unsigned int _pivot_index = _half_size; //"Silly" pivot policy. Random-pivot instead? http://stackoverflow.com/questions/11498304/generate-random-numbers-in-c-at-compile-time
using _pivot = typename dl32TypeAt<_pivot_index,dl32TypeList<Ns...>>::type;
using _right = _right_sublist<_pivot>; //"Call" to reordered right sublist computation
using _left = _left_sublist<_pivot>; //"Call" to reordered left sublist computation
public:
/* STEP 2: Recursive "call" to quicksort passing the two generated sublists */
using result = typename dl32Merge< typename _quicksort< _left::size , _left >::result , typename _quicksort< _right::size , _right >::result >::result;
};
public:
using result = typename _quicksort<UINT_LIST::size,UINT_LIST>::result; //"Call" to quicksort computation;
};
/* input/output printing tools */
template<typename OUTPUT>
struct print_output;
template<>
struct print_output<empty_uint_list>{ static void print() { cout << endl << endl; } };
template<typename HEAD , typename... TAIL>
struct print_output<dl32TypeList<HEAD,TAIL...>>
{
static void print()
{
cout << HEAD::value << (sizeof...(TAIL) > 0 ? "," : "");
print_output<dl32TypeList<TAIL...>>::print();
}
};
/* unsigned int lists generator */
template<unsigned int BEGIN , unsigned int END>
class uint_list_generator
{
private:
template<unsigned int _CURRENT,unsigned int _END>
struct _generator
{
using result = typename dl32Merge<uint_list<_CURRENT>,typename _generator<(BEGIN <= END ? _CURRENT + 1 : _CURRENT - 1) , _END>::result>::result;
};
template<unsigned int _END>
struct _generator<_END,_END>
{
using result = uint_list<_END>;
};
public:
using result = typename _generator<BEGIN,END>::result;
};
using input = typename uint_list_generator<0,499>::result;
using output = typename quicksort<input>::result;
int main()
{
print_output<input>::print();
print_output<output>::print();
return 0;
}
The algorithm works perfectly (After the compiler has eaten 4GB of RAM, and waste two minutes to compile an execution of a 500 elements list...).
As you can see, i used a bigger-or-equal comparer in the quicksort implementation. My question is: There are any method to pass the comparer through a template parameter?
The problem is that the algorithm uses lists of unsigned int wrappers as data (See "uint_list" declaration at the beginning of the code), and comparers expect uint wrappers as parameters. So i cannot pass a "generic" comparer through the quicksort template.
What about a template template parameter:
template <typename UINT_LIST,
template <typename UINT1, typename UINT2> class compare = less_than>
class quicksort
{
...
using result = typename dl32tmp_if<compare<FIRST,LAST>::value, ...
};
...
using output = typename quicksort<input, bigger_than>::result;
Besides, with such signature, you are not restricted to unsigned int-s at all.
Other than that, sometimes it may be useful to use a wrapper class hiding the template inside to mimic a template typedef.

C++ recursive type traits

I'm trying to implement a template class (named Get<> here) that, given a structure H, the type Get<H>::type is the H itself if the qualified-id H::der doesn't exist, and is Get<H::der>::type otherwise. I can't understand what's wrong with the following code:
#include <iostream>
#include <typeinfo>
using namespace std;
template<class U, class V = void>
struct Get
{
static const char id = 'A';
typedef U type;
};
template<class U>
struct Get<U,typename U::der>
{
static const char id = 'B';
typedef typename Get<typename U::der>::type type;
};
struct H1
{ };
struct H2
{ typedef double der; };
struct H3
{ typedef void der; };
struct H4
{ typedef H2 der; };
void print(char id, const char* name)
{
cout << id << ", " << name << endl;
}
int main(int , char *[])
{
print(Get<H1>::id, typeid(Get<H1>::type).name()); // prints "A, 2H1", OK
print(Get<H2>::id, typeid(Get<H2>::type).name()); // prints "A, 2H2", why?
print(Get<H3>::id, typeid(Get<H3>::type).name()); // prints "B, v" , OK
print(Get<H4>::id, typeid(Get<H4>::type).name()); // prints "A, 2H4", why?
}
I'd like some help to make this code behave as expected. More specifically, I wish that Get< H2 >::type was equal to double, and the same for Get< H4 >::type.
The template Get<> has a default template parameter -- this is very dangerous. Depending on whether V is equal int, void or double you get different results. This is what happens:
Get<H2>::type is Get<H2, void> on the first place (with id='A'). Now comes the check, whether there is an specialization of it. Your B is Get<U,typename U::der> which becomes Get<U, double>. But this doesn't match whith Get<H2, void>, so A is chosen. Things get interesting with Get<H2>::type. Then the variant B is also Get<U, void> and provides a better match. However, the approach can't work for all types.
This is how I would have implemented Get:
template<class U>
class Get
{
template <typename T, typename = typename T::der>
static typename Get<typename T::der>::type test(int);
template <typename T>
static T test(...);
public:
typedef decltype(test<U>(0)) type;
};
While I give a +1 to #ipc answer and it is very well for C++11 enabled compilers, for C++03 compilers you should use a different approach, since default value for template arguments of a function is not supported in C++03. So I have this code:
template<class U, class V = void>
struct Get
{
static const char id = 'A';
typedef U type;
};
template< class T >
struct is_type {
static const bool value = true;
};
template<class U>
struct Get<U,
typename std::tr1::enable_if<is_type<typename U::der>::value, void>::type>
{
static const char id = 'B';
typedef typename Get<typename U::der>::type type;
};

Restrict integer template parameter

I've a code smth like this:
template<int N, typename T>
class XYZ {
public:
enum { value = N };
//...
}
Is there a way to restrict N in some way? Specifically I want to allow compilation only if N is divided by some number, let's say 6.
So it turned out to be not just a type restriction.
Preferred way is to do this without Boost.
One C++03 approach:
template<int X, int Y>
struct is_evenly_divisible
{
static bool const value = !(X % Y);
};
template<int N, typename T, bool EnableB = is_evenly_divisible<N, 6>::value>
struct XYZ
{
enum { value = N };
};
template<int N, typename T>
struct XYZ<N, T, false>; // undefined, causes linker error
For C++11, you can avoid some boilerplate and give a nicer error message:
template<int N, typename T>
struct XYZ
{
static_assert(!(N % 6), "N must be evenly divisible by 6");
enum { value = N };
};
I leave this here for the future, since I couldn't find a good example online at the time of posting.
The C++20 way with concepts:
template<int X, int Y>
concept is_evenly_divisible = X % Y == 0;
template <int N, int M> requires is_evenly_divisible<N, M>
struct XYZ
{
enum class something { value = N };
};
XYZ<12, 6> thing; // OK
//XYZ<11, 6> thing; // Error
Or even shorter:
template <int N, int M> requires (N % M == 0)
struct XYZ
{
enum class something { value = N };
};

Type inference in Visual C++ 2008

Is there some vendor-specific type inference mechanism in Microsoft Visual C++ 2008, similar to the standardized auto or decltype in C++0x?
No, nothing like that, standard nor vendor specific nor addon. You'll have to upgrade to VS2010, it implements auto.
Quoting from a Boost mailing list article by Arkadiy Vertleyb:
God only knows what else can be found
inside this compiler if one is willing
to dig real deep.
For example, Igor' Chesnokov from RSDN
(Russian Software Development Network)
has found a way to implement typeof()
that does not require registration,
and probably has compile-time
performance of a native typeof.
How? Apparently, some weird "feature"
of Visual C++ allowed him to twick a
template body at the moment of
instantiation, when additional context
is available, thus "registering"
classes on the fly, at the moment of
taking typeof().
Microsoft-specific "bugfeatures" are
generally not in the area of my
interests. However I do realize that,
on the Microsoft compiler, this might
look much more attractive then
anything Peder and I have implemented.
And even though I realize that this
might be a serious competition, I
would feel really bad not to mention
this here:
http://rsdn.ru/Forum/?mid=1094305
And quoting Igor Chesnokov's code from the page referenced by the quoted link above:
// type_of() evil implementation for VC7
//
// (c) Chez
// mailto:chezu#pisem.net
#include "stdafx.h"
// This file contains:
// 1) type_id(type)
// 2) var_type_id(expersssion)
// 3) type_of(expression)
// IMPLEMENTATION
template<int ID>
class CTypeRegRoot
{
public:
class id2type;
};
template<typename T, int ID>
class CTypeReg : public CTypeRegRoot<ID>
{
public:
class CTypeRegRoot<ID>::id2type // This uses nice VC6-VC7 bugfeature
{
public:
typedef T Type;
};
typedef void Dummy;
};
template<int N>
class CCounter;
// TUnused is required to force compiler to recompile CCountOf class
template<typename TUnused, int NTested = 0>
class CCountOf
{
public:
enum
{
__if_exists(CCounter<NTested>) { count = CCountOf<TUnused, NTested + 1>::count }
__if_not_exists(CCounter<NTested>) { count = NTested }
};
};
template<class TTypeReg, class TUnused, int NValue> // Helper class
class CProvideCounterValue
{
public:
enum { value = NValue };
};
// type_id
#define type_id(type) \
(CProvideCounterValue< \
/*register TYPE--ID*/ typename CTypeReg<type, CCountOf<type >::count>::Dummy, \
/*increment compile-time Counter*/ CCounter<CCountOf<type >::count>, \
/*pass value of Counter*/CCountOf<type >::count \
>::value)
// Lets type_id() be > than 0
class __Increment_type_id { enum { value = type_id(__Increment_type_id) }; };
template<int NSize>
class sized
{
private:
char m_pad[NSize];
};
template<typename T>
typename sized<type_id(T)> VarTypeID(T&);
template<typename T>
typename sized<type_id(const T)> VarTypeID(const T&);
template<typename T>
typename sized<type_id(volatile T)> VarTypeID(volatile T&);
template<typename T>
typename sized<type_id(const volatile T)> VarTypeID(const volatile T&);
// Unfortunatelly, var_type_id() does not recognize references
#define var_type_id(var) \
(sizeof(VarTypeID(var)))
// type_of
#define type_of(expression) \
/* This uses nice VC6-VC7 bugfeature */ \
CTypeRegRoot<var_type_id(expression)>::id2type::Type
// auto_operator
#define auto_operator(arg1, arg2, op) \
type_of(instance(arg1) op instance(arg2)) operator op
// TEST
class A
{
public:
friend static const char* operator +(const A& a, const A& b)
{
return "chijik-pijik";
}
};
template<typename T>
class Plus
{
public:
friend static type_of(T() + T()) operator +(const Plus<T>& a, const Plus<T>& b)
{
return a.m + b.m;
}
T m;
};
int _tmain(int argc, _TCHAR* argv[])
{
Plus<A> a1, a2;
const char* x = a1 + a2;
return 0;
}
Now I haven't tried this code, and, since it uses compiler-specific stuff, do note that it's for MSVC 7.x. So it may or may not work with a later version. Hopefully it does?
Cheers & hth.,
Use BOOST. Or if you don't want to trudge with all of BOOST, here is a snippet that will work with Visual Studio 2008 (but probably no other version):
namespace typeid_detail {
template <int N>
struct encode_counter : encode_counter<N - 1> {};
template <>
struct encode_counter<0> {};
char (*encode_index(...))[5];
// need to default to a larger value than 4, as due to MSVC's ETI errors. (sizeof(int) = 4)
struct msvc_extract_type_default_param {};
template <typename ID, typename T = msvc_extract_type_default_param>
struct msvc_extract_type;
template <typename ID>
struct msvc_extract_type<ID, msvc_extract_type_default_param> {
template <bool>
struct id2type_impl;
typedef id2type_impl<true> id2type;
};
template <typename ID, typename T>
struct msvc_extract_type : msvc_extract_type<ID,msvc_extract_type_default_param> {
template <>
struct id2type_impl<true> { // VC8.0 specific bugfeature
typedef T type;
};
template <bool>
struct id2type_impl;
typedef id2type_impl<true> id2type;
};
template <typename T, typename ID>
struct msvc_register_type : msvc_extract_type<ID, T> {
};
template <int i>
struct int_ {
enum { value = i };
};
template <int ID>
struct msvc_typeid_wrapper {
typedef typename msvc_extract_type<int_<ID> >::id2type id2type;
typedef typename id2type::type type;
};
template <>
struct msvc_typeid_wrapper<1> {
typedef msvc_typeid_wrapper<1> type;
};
// workaround for ETI-bug for VC6 and VC7
template <>
struct msvc_typeid_wrapper<4> {
typedef msvc_typeid_wrapper<4> type;
};
// workaround for ETI-bug for VC7.1
#define TYPEOF_INDEX(T) (sizeof(*encode_index((encode_counter<405/*1005*/>*)0))) // this needs to be lower for VS 2008, otherwise causes too deep templates
#define TYPEOF_NEXT_INDEX(next) friend char (*encode_index(encode_counter<next>*))[next];
template <typename T>
struct encode_type {
static const unsigned value = TYPEOF_INDEX(T);
// get the next available compile time constants index
typedef typename msvc_register_type<T,int_<value> >::id2type type;
// instantiate the template
static const unsigned next = value + 1;
// set the next compile time constants index
TYPEOF_NEXT_INDEX(next);
// increment the compile time constant (only needed when extensions are not active)
};
template <class T>
struct sizer {
typedef char(*type)[encode_type<T>::value];
};
template <typename T> typename sizer<T>::type encode_start(T const&);
// a function that converts a value to size-encoded type (not implemented, only needed for type inference)
template <typename Organizer, typename T>
msvc_register_type<T, Organizer> typeof_register_type(const T&, Organizer* = 0);
} // ~typeid_detail
#define type_of(expr) \
typeid_detail::msvc_typeid_wrapper<sizeof(*typeid_detail::encode_start(expr))>::type
And use e.g. as:
int x = 123;
float y = 456.0f;
typedef type_of(x+y) int_plus_float;
int_plus_float value = x + y;
And of course refer to BOOST license when using this.