Simplifying template parameters - c++

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

Related

passing template for later use in other struct/class context

I have some classes which need to define a template which can be used in generic code parts as type later.
In real world code the forwarded templates have a lot more parameters and it is not really nice to read the code.
Q: Is it possible to define the template in some syntax instead of writing it as alias template as given in the following example? I simple would avoid repeating of all the template parameters two times of each alias declaration.
The real world template also have some non type template parameters so simply using <PARMS...> will not work.
Example:
#include <iostream>
template < typename T>
struct A
{
static void Do(T t) { std::cout << "A " << t << std::endl;}
};
template < typename T>
struct B
{
static void Do(T t) { std::cout << "B " << t << std::endl;}
};
struct UseA
{
// using the alias template works as expected, but...
template < typename T>
using USE = A<T>;
// is there any chance to write something like:
// using USE = A;
// to simply avoid replication of template parameters?
};
struct UseB
{
template < typename T>
using USE = B<T>;
};
int main()
{
UseA::USE<int>::Do(1);
UseB::USE<std::string>::Do("Hallo");
}
What you are asking cannot be done. You always have to define the whole type list. The reason is, that one could have default overloads for the same type. For example, in the following A<int, 3>, A<int> and A<> are all valid. The compiler does not know which one you want:
template <class T, int Value = 42>
struct A {};
auto test() {
auto a = A<int, 3>{};
auto b = A<int>{};
auto c = A<>{};
}
If you don't want to write the type lists, I would recommend you to switch to templatizing more of your classes, so they don't need to know about the implementation details. Like:
#include <iostream>
template < typename T>
struct A
{
static void Do(T t) { std::cout << "A " << t << std::endl;}
};
template < typename T>
struct B
{
static void Do(T t) { std::cout << "B " << t << std::endl;}
};
template < typename T>
struct Use
{
using USE = T;
};
int main()
{
Use<A<int>>::USE::Do(1);
Use<B<std::string>>::USE::Do("Hallo");
}
Or alternatively, use containers for your non template type values:
#include <iostream>
template < int Value >
struct INT
{
static constexpr int value = Value;
};
template < bool Value >
struct BOOL
{
static constexpr bool value = Value;
};
template < typename T, typename Value >
struct A
{
static void Do(T t) { std::cout << "A " << t << Value::value << std::endl;}
};
template < typename T, typename Value>
struct B
{
static void Do(T t) { if (Value::value) std::cout << "B " << t << std::endl;}
};
template <template<typename...> class T, typename ...Param>
using USE = T<Param...>;
int main()
{
USE<A, int, INT<42>>::Do(1);
USE<B, std::string, BOOL<true>>::Do("Hallo");
}

Calling template function from inner class

I have a class like this to call a function depending on the type. I try to compile it, but have error error C2059 syntax error : 'template'
class A
{
call_1()
{
B<type> b;
b.template say(i);
}
template<class T>
struct B
{
template <typename T, typename I>
T say(I i) {
return word;
}
};
template<>
struct B<void>
{
template <typename T, typename I>
void say(I i) {
/**/
}
};
}
What am I doing wrong?
First, let's rewrite your example into something that is readable and is closer to being compilable, and we also print "1" or "2" in say() to know which function gets called:
#include <iostream>
using type = int;
class A {
void call_1() {
B<type> b;
int i = 0;
b.template say(i);
}
template<class T>
struct B
{
template <typename T, typename I>
T say(I i) {
std::cout << "1\n";
return T();
}
};
template<>
struct B<void>
{
template <typename T, typename I>
void say(I i) {
std::cout << "2\n";
}
};
};
OK, so first, you are trying to specialize B inside of A. This is not allowed, so let't move it outside of A:
using type = int;
class A {
void call_1() {
B<type> b;
int i = 0;
b.template say(i);
}
template<class T>
struct B
{
template <typename T, typename I>
T say(I i) {
std::cout << "1\n";
return T();
}
};
};
template<>
struct A::B<void>
{
template <typename T, typename I>
void say(I i) {
std::cout << "2\n";
}
};
Next up, you are using the same template parameter (T) in both B and say(). You don't need to repeat T, so let's delete it:
using type = int;
class A {
void call_1() {
B<type> b;
int i = 0;
b.template say(i);
}
template<class T>
struct B
{
template <typename I>
T say(I i) {
std::cout << "1\n";
return T();
}
};
};
template<>
struct A::B<void>
{
template <typename I>
void say(I i) {
std::cout << "2\n";
}
};
Finally, call_1() cannot be defined before the specialization of A::B, so we need to move it outside too:
using type = int;
class A {
void call_1();
template<class T>
struct B
{
template <typename I>
T say(I i) {
std::cout << "1\n";
return T();
}
};
};
template<>
struct A::B<void>
{
template <typename I>
void say(I i) {
std::cout << "2\n";
}
};
void A::call_1() {
B<type> b;
int i = 0;
b.template say(i);
}
This should now compile and do what you want. Calling call_1() will print 1. If you change the type from int to void:
using type = void;
it will print 2.

MSVC2015 decltype parameter type in overloaded template function

Is the following program compliant C++11? If so, do you know of a specific MSVC bug that triggers it? and/or a possible work-around?
#include <iostream>
struct A {};
struct B {};
constexpr A aaa = {};
constexpr B bbb = {};
template <typename T>
void foo(T, decltype(aaa)) { std::cout << "a"; }
template <typename T>
void foo(T, decltype(bbb)) { std::cout << "b"; }
// ^ C2995 'void foo(T,unknown-type)': function template has already been defined
int main()
{
foo(0, aaa);
foo(0, bbb);
}
If the actual types are substituted for decltype then it works, but in practice these types are too complicated to reproduce and I'd prefer not to have aliases for them.
Works for me (VS 2015 / v140) with the following minor modification:
#include <iostream>
struct A {};
struct B {};
constexpr A aaa = {};
constexpr B bbb = {};
using A_type = decltype(aaa);
using B_type = decltype(bbb);
template <typename T>
void foo(T, A_type) { std::cout << "a"; }
template <typename T>
void foo(T, B_type) { std::cout << "b"; }
int main()
{
foo(0, aaa);
foo(0, bbb);
}
But this variant yields the same error (not sure what to make of it):
template <typename T>
struct TypeWrapper {
using type = T;
};
template <typename T>
void foo(T, typename TypeWrapper<decltype(aaa)>::type) { std::cout << "a"; }
template <typename T>
void foo(T, typename TypeWrapper<decltype(bbb)>::type) { std::cout << "b"; }

How to build Type2Int from Int2Type?

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

C++ template specialization of constructor

I have a templated class A<T, int> and two typedefs A<string, 20> and A<string, 30>.
How do I override the constructor for A<string, 20> ? The following does not work:
template <typename T, int M> class A;
typedef A<std::string, 20> one_type;
typedef A<std::string, 30> second_type;
template <typename T, int M>
class A {
public:
A(int m) {test= (m>M);}
bool test;
};
template<>
one_type::one_type() { cerr << "One type" << endl;}
I would like the class A<std::string,20> to do something that the other class doesn't. How can I do this without changing the constructor A:A(int) ?
The only thing you cannot do is use the typedef to define the constructor. Other than that, you ought to specialize the A<string,20> constructor like this:
template<> A<string,20>::A(int){}
If you want A<string,20> to have a different constructor than the generic A, you need to specialize the whole A<string,20> class:
template<> class A<string,20> {
public:
A(const string& takethistwentytimes) { cerr << "One Type" << std::endl; }
};
Assuming your really meant for A::test to be publicly accessible, you could do something like this:
#include <iostream>
template <int M>
struct ABase
{
ABase(int n) : test_( n > M )
{}
bool const test_;
};
template <typename T, int M>
struct A : ABase<M>
{
A(int n) : ABase<M>(n)
{}
};
template <typename T>
A<T, 20>::A(int n)
: ABase<20>(n)
{ std::cerr << "One type" << std::endl; }
Kick the tires:
int main(int argc, char* argv[])
{
A<int, 20> a(19);
std::cout << "a:" << a.test_ << std::endl;
A<int, 30> b(31);
std::cout << "b:" << b.test_ << std::endl;
return 0;
}
Late but a very elegant solution:
C++ 2020 introduced Constraints and Concepts. You can now conditionally enable and disable constructors and destructors!
#include <iostream>
#include <type_traits>
template<class T>
struct constructor_specialized
{
constructor_specialized() requires(std::is_same_v<T, int>)
{
std::cout << "Specialized Constructor\n";
};
constructor_specialized()
{
std::cout << "Generic Constructor\n";
};
};
int main()
{
constructor_specialized<int> int_constructor;
constructor_specialized<float> float_constructor;
};
Run the code here.
This may be a little bit late, but if you have access to c++11 you can use SFINAE to accomplish just what you want:
template <class = typename std::enable_if<
std::is_same<A<T,M>, A<std::string, 20>>::value>::type // Can be called only on A<std::string, 20>
>
A() {
// Default constructor
}
Working example
How about :
template<typename T, int M, bool dummy = (M > 20) >
class A {
public:
A(int m){
// this is true
}
};
template<typename T, int M>
class A<T,M,false> {
public:
A(int m) {
//something else
}
};
You can't with your current approach. one_type is an alias to a particular template specialization, so it gets whatever code the template has.
If you want to add code specific to one_type, you have to declare it as a subclass of A specialization, like this:
class one_type:
public A<std::string, 20>
{
one_type(int m)
: A<str::string, 20>(m)
{
cerr << "One type" << endl;
}
};
The best solution I've been able to come up with for this situation is to use a "constructor helper function":
template <typename T, int M> class A;
typedef A<std::string, 20> one_type;
typedef A<std::string, 30> second_type;
template <typename T, int M>
class A {
private:
void cons_helper(int m) {test= (m>M);}
public:
A(int m) { cons_helper(m); }
bool test;
};
template <>
void one_type::cons_helper(int) { cerr << "One type" << endl;}