I have Int2Type specialization
struct A;
struct B;
template<int i> Int2Type;
template<> Int2Type<1> { typedef A type; };
template<> Int2Type<2> { typedef B type; };
Can I build reverse Type2Int specialization automatically? Type2Int<A>::value==1 and so on
Thank you
PS Of course, I can define macro
#define I2T(i, T) template<> Int2Type<i> { typedef T type; }; template<> Type2Int<T> { static const int value = i; };
but I don't want change existing code, may be exists some other way...
update
A, B and others lives in different files
common.h
template<int i> Int2Type;
a.h
struct A;
template<> Int2Type<1> { typedef A type; };
b.h
struct B;
template<> Int2Type<2> { typedef B type; };
I need two compile-time "maps" - type by int and int by type;
Int2Type<1>::type a;
someFunc(Type2Int<A>::value)
Directly? No. Such a thing would be impossible in C++. But, with an intermediate type, we could implement such a thing ourselves with a few helpers.
Without C++11, check out the Boost.MPL library. Specifically, we want boost::mpl::vector:
typedef boost::mpl::vector<A, B> IndexedTypes;
template <int I>
struct Int2Type {
typedef typename boost::mpl::at<IndexedTypes,
boost::mpl::int_<I - 1>
>::type type;
};
template <typename T>
struct Type2Int {
typedef typename boost::mpl::begin<IndexedTypes>::type begin;
typedef typename boost::mpl::find<IndexedTypes, T>::type iter;
static const int value = boost::mpl::distance<begin, iter>::type::value + 1;
};
That should give you Int2Type<1>::type as A, and Type2Int<B> as 2.
With C++11, we can write these as short metafunctions based on a variadic sequence:
template <typename...> struct sequence { };
using IndexedTypes = sequence<A, B>;
can you re-arrange your code to be more like this?
struct A;
struct B;
template<int I, class Type>
struct Int2Type
{
static const int value = I;
typedef Type type;
};
using type1 = Int2Type<1, A>;
using type2 = Int2Type<2, B>;
This works for me:
#include <iostream>
int getNextInt()
{
static int next = 0;
return ++next;
}
template <typename T> struct TypeToInt
{
static const int value;
};
template <typename T> const int TypeToInt<T>::value = getNextInt();
struct A;
struct B;
struct C;
int main()
{
std::cout << TypeToInt<A>::value << std::endl;
std::cout << TypeToInt<B>::value << std::endl;
std::cout << TypeToInt<C>::value << std::endl;
}
Output:
1
2
3
Related
I have a template that accepts class F and int X. Class F has a static inline double eval(double x) method. Based on the result returned by eval I need to choose between int and long types - smallest possible that will fit the result (converted to a round number as it's double).
I tried doing it this way but I get Non-type template argument is not a constant expression error.
template <class F, int X>
struct DEDUCTOR {
typedef SELECT<-32768 < F::eval(X) && F::eval(X) < 32767> result;
}
where SELECT is defined this way:
template <bool is_int>
struct SELECT {};
template <>
struct SELECT<true> {
typedef int type;
};
template <>
struct SELECT<false> {
typedef long type;
};
Is there any way to create such template?
============================
UPDATE:
According to the advice, I added constexpr to the eval function. It works now, but now always. Full example:
#include <iostream>
#include <math.h>
#include <typeinfo>
struct X {
static constexpr double eval(double x) { return x; };
};
template<class L, class R>
struct MULT {
static constexpr double eval(double x) {
return L::eval(x) * R::eval(x);
}
};
template<class L, class R>
struct DIV {
static constexpr double eval(double x) {
return L::eval(x) / R::eval(x);
}
};
template <bool is_int>
struct SELECT {
typedef long type;
};
template <>
struct SELECT<true> {
typedef int type;
};
template<class F, int X>
struct DEDUCTOR {
typedef typename SELECT<-32768 < F::eval(X) && F::eval(X) < 32767>::type result;
};
int main() {
// typedef MULT<MULT<X, X>, X> F; // works
typedef DIV<DIV<X, X>, X> F; // doesn't work
typedef DEDUCTOR<F, 0> deductor;
std::cout << typeid(deductor::result).name() << std::endl;
return 0;
}
Your main problem is this line:
typedef SELECT<-32768 < F::eval(X) && F::eval(X) < 32767> result;
it should be:
typedef typename SELECT < -32768 < F::eval(X) && F::eval(X) < 32767 > ::type result;
NOTE: trailing "::type" to actually refer to the type from your SELECT structs, and leading "typename" since it's a dependent type.
Below is a working version. Note that I slightly changed the SELECT as well, but this isn't required to compile.
template <bool is_int>
struct SELECT {
typedef long type;
};
template <>
struct SELECT<true> {
typedef int type;
};
template <class F, int X>
struct DEDUCTOR {
typedef typename SELECT < -32768 < F::eval(X) && F::eval(X) < 32767 > ::type result;
};
struct myS
{
static constexpr double eval(double x) { return x; }
};
int main()
{
std::cout << typeid(DEDUCTOR<myS, 100>::result).name() << std::endl;
std::cout << typeid(DEDUCTOR<myS, 100000>::result).name() << std::endl;
}
Take the following struct:
template<typename T,T value>
struct A{
};
I would like to use it like this:
A<12> a; //A<12> should become A<int,12>
But this is not allowed. Why is it not allowed? (and is there a workaround?)
Not sure what you want, but perhaps this?
#include <iostream>
template <typename T, T value>
struct A {
void foo() const { std::cout << "A<int, " << value << ">::foo called\n"; }
};
// Sample partial specialization that you might want.
template <std::size_t value>
struct A<std::size_t, value> {
void foo() const { std::cout << "A<std::size_t, " << value << ">::foo called\n"; }
};
template <int N>
using B = A<int, N>;
template <int N, typename T = int>
using C = A<T, static_cast<T>(N)>;
int main() {
B<12> a;
a.foo(); // A<int, 12>::foo called
C<12> c;
c.foo(); // A<int, 12>::foo called
C<12, std::size_t> d;
d.foo(); // A<std::size_t, 12>::foo called
}
Maybe the closest you're going to get is to use a meta-factory:
template<class T, T value>
struct A
{};
template<class T = int>
struct factory
{
template<T V> using A = ::A<T, V>;
};
int main()
{
auto x = factory<>::A<12> {};
auto y = factory<short>::A<45> {};
}
I'm trying to implement templated structs that take a version parameter.
Here's a simplified example:
template<int Version, class Enable = void>
struct Foo
{
};
template<int Version, class Enable = void>
struct Bar
{
};
/* Base Version of Foo */
template<int Version>
struct Foo<Version, typename enable_if<(Version > 0)>::type>
{
int i;
};
/* Base Version of Bar */
template<int Version>
struct Bar<Version, typename enable_if<(Version > 0)>::type>
{
Foo<Version> foo;
float f;
};
/* Version 2 of Bar */
template<int Version>
struct Bar<Version, typename enable_if<(Version >= 2)>::type>
{
Foo<Version> foo;
float f;
int extraParam;
};
With this approach, there is ambiguity when I use "Bar<2>", because 2 satisfies both the base version's condition (Version > 0) and the version 2 condition (Version >= 2).
I could change the base to require "Version > 0 && Version < 2", but I was hoping to avoid having to do that everywhere. Is there a better way to tell the compiler "Use the highest matching version" for a given template ?
Using the example link provided by dyp, I was able to solve the problem with recursion.
#include <iostream>
#include <type_traits>
using namespace std;
template<int Version>
struct Foo
{
constexpr static bool is_valid = false;
};
template<int Version>
struct Bar
{
constexpr static bool is_valid = false;
};
struct ValidVersion { constexpr static bool is_valid = true; };
/* Base Version of Foo */
template<>
struct Foo<0> : ValidVersion
{
int i;
};
/* Base Version of Bar */
template<>
struct Bar<0> : ValidVersion
{
Foo<0> foo;
float f;
};
/* Version 2 of Bar */
template<>
struct Bar<2> : ValidVersion
{
Foo<2> foo;
float f;
int extraParam;
int extraParam2;
};
template<template<int V> class _Tp, int Version>
struct VersionSelectorImpl
{
template<class T>
struct wrap { using type = T; };
using type = typename std::conditional<_Tp<Version>::is_valid, wrap<_Tp<Version>>, VersionSelectorImpl<_Tp, Version-1>>::type::type;
};
template<template<int V> class _Tp, int Version>
using VersionSelector = typename VersionSelectorImpl<_Tp, Version>::type;
int main() {
cout << "sizeof(<Bar, 1>): " << sizeof(VersionSelector<Bar, 1>) << '\n';
cout << "sizeof(<Bar, 2>): " << sizeof(VersionSelector<Bar, 2>) << '\n';
}
Output:
sizeof(<Bar, 1>): 12
sizeof(<Bar, 2>): 16
#include <iostream>
#include <array>
using namespace std;
constexpr int N = 10;
constexpr int f(int x) { return x*2; }
typedef array<int, N> A;
template<int... i> struct F { constexpr A f() { return A{{ f(i)... }}; } };
template<class X, class Y> struct C;
template<int... i, int... j>
struct C<F<i...>, F<j...>> : F<i..., (sizeof...(i)+j)...> {};
template<int n> struct S : C<S<n/2>, S<n-n/2>> {}; // <--- HERE
template<> struct S<1> : F<0> {};
constexpr auto X = S<N>::f();
int main()
{
cout << X[3] << endl;
}
I'm getting:
test.cpp:15:24: error: invalid use of incomplete type ‘struct C<S<5>, S<5> >’
I suspect this is because the definition of S is using itself as a base class. (Correct?)
What is the best way to fix this?
Update:
Here is the fixed version:
#include <iostream>
#include <array>
using namespace std;
constexpr int N = 10;
constexpr int f(int x) { return x*2; }
typedef array<int, N> A;
template<int... i> struct F { static constexpr A f() { return A{{ ::f(i)... }}; } };
template<class A, class B> struct C {};
template<int... i, int... j> struct C<F<i...>, F<j...>> : F<i..., (sizeof...(i)+j)...>
{
using T = F<i..., (sizeof...(i)+j)...>;
};
template<int n> struct S : C<typename S<n/2>::T, typename S<n-n/2>::T> {};
template<> struct S<1> : F<0> { using T = F<0>; };
constexpr auto X = S<N>::f();
int main()
{
cout << X[3] << endl;
}
Define C instead of just declaring it.
template<class X, class Y> struct C {};
In the place you use it the partial specialization does not match and
the primary template is instantiated, which is just a declaration.
You may wonder why that specialization is not considered: specializations don't consider conversions, but just the static type. That's why they are so treacherously incompatible with inheritance.
Could you just delegate S::f instead of using inheritance?
template<int n> struct S {
constexpr A f() { return C<S<n/2>, S<n-n/2>>::f(); }
};
I have something like:
struct A { ... };
struct B { ... };
struct C { ... };
class MyEnum {
public:
enum Value { a, b, c; }
}
template<typename T> MyEnum::Value StructToMyEnum();
template<>
MyEnum::Value StructToMyEnum<A>()
{
return MyEnum::a;
}
template<>
MyEnum::Value StructToMyEnum<B>()
{
return MyEnum::b;
}
I basically want to get a directly by calling soemthing like
StructToMyEnum<A>();
This is the best I could come up with, but when I compile I get multiple definition of 'MyEnum::Value StructToMyEnum<A>()' errors when trying to link.
Any recommendations on the best way to map types to enums as per this example?
You can map types to enums at compile time:
#include <iostream>
struct A { int n; };
struct B { double f; };
struct C { char c; };
class MyEnum
{
public:
enum Value { a, b, c };
};
template<typename T> struct StructToMyEnum {};
template<> struct StructToMyEnum<A> {enum {Value = MyEnum::a};};
template<> struct StructToMyEnum<B> {enum {Value = MyEnum::b};};
template<> struct StructToMyEnum<C> {enum {Value = MyEnum::c};};
int main (int argc, char* argv[])
{
std::cout << "A=" << StructToMyEnum<A>::Value << std::endl;
return 0;
}
The multiple definitions are because you need to either add the inline keyword or push the implementation of your specializations into a cpp file, leaving only the declarations of such in the header.
You could probably use mpl::map to write a sort-of generic version. Something like so:
struct A {};
struct B {};
struct C {};
enum Value { a,b,c };
template < typename T >
Value get_value()
{
using namespace boost::mpl;
typedef mpl::map
<
mpl::pair< A, mpl::int_<a> >
, mpl::pair< B, mpl::int_<b> >
, mpl::pair< C, mpl::int_<c> >
> type_enum_map;
typedef typename mpl::at<type_enum_map, T>::type enum_wrap_type;
return static_cast<Value>(enum_wrap_type::value);
}
Why don't you just make a static member variable of type enum and add it to your structs?
struct A
{
//Stuff
static MyEnum enumType; // Don't forget to assign a value in cpp
};
Than you can just do:
MyEnum e = StructA::enumType;
Or do you really want to use templates?