Overloading template classes by template parameter number - c++

Is it possible to have multiple versions of the same class which differ only in the number of template arguments they take?
For instance:
template<typename T>
class Blah {
public:
void operator()(T);
};
template<typename T, typename T2>
class Blah {
public:
void operator()(T, T2);
};
I'm trying to model functor type things which can take a variable number of arguments (up to the number of different templates that were written out).

The simplest answer would be to have just one template, with the maximum number you want to support and use void for a default type on all but the first type. Then you can use a partial specialization as needed:
template<typename T1, typename T2=void>
struct foo {
void operator()(T1, T2);
};
template <typename T1>
struct foo<T1, void> {
void operator()(T1);
};
int main() {
foo<int> test1;
foo<int,int> test2;
test1(0);
test2(1,1);
}

A template can have only one base definition. If you need a variable number of arguments and you don't want to use "null type" constructions as #awoodland suggests, and if you have a C++0x compiler, then you can use variadic templates:
template <typename ...Dummy> struct foo; // base case, never instantiated!
template <typename T> struct foo<T> { /*...*/ }; // partial spec. for one parameter
template <typename T, typename U> struct foo<T, U> { /*...*/ }; // ditto for two

This is untested code, I don't have a version of boost handy, but here goes anyway
#include "boost/tuple.h"
template <class T>
class Blah;
template <class T>
class Blah< boost::tuple<T> >
{
void operator()(T arg);
};
template <class T, class U>
class Blah< boost::tuple<T, U> >
{
void operator()(T arg1, U arg2);
};
etc. etc.

Related

Templated Using with Nested Template

The following code does not work because the inferred template parameter F is std::tuple, whereas I want it to be Foo - the former takes two template parameters and the latter takes one.
#include <tuple>
template <typename T>
using Foo = std::tuple<int, T>;
template <template <typename> class F>
void foo(F<std::string> bar) {}
void test() {
foo(Foo<std::string>());
}
Is there any way to make type inference work with the using statement rather than turning Foo into it's own class?
#include <tuple>
template <typename T>
class Foo {
std::tuple<int, T> bar;
};
template <template <typename> class F>
void foo(F<std::string> bar) {}
void test() {
foo(Foo<std::string>());
}
More Info
I am using C++17's std::variant along with using to alias types that are generic on a single type and I would prefer to declare these with using statements rather than creating wrapper classes for each one. Something like this:
// Assuming Plus, Minus, etc all exist
template <typename T>
using Operation = std::variant<Plus<T>, Minus<T>, Times<T>>;
Building a Haskell-Style Functor
The point of this exercise is to build a small functor library loosely based on Haskell's functor typeclass. I have defined the "typeclass" like this:
template <template <typename> class F>
class Functor {
public:
template <typename T, typename U>
static F<U> fmap(std::function<U(T)> f, F<T> functor);
};
But I also wanted to add some sugar so that you can create a general mapper that will map a function over any function type without pre-specifying the functor type:
template <typename T, typename U>
struct FMap {
FMap(std::function<U(T)> f) : f_(f) {}
template <template <typename> class F>
F<U> operator()(F<T> functor) {
return Functor<F>::fmap(f_, functor);
}
private:
std::function<U(T)> f_;
};
template <typename T, typename U>
FMap<T, U> fmap(std::function<U(T)> f) {
return FMap<T, U>(f);
}
This works well with a simple value-wrapper functor:
template <typename T>
class Value {
public:
Value(T value) : value_(value) {}
const T& value() const {
return value_;
}
private:
T value_;
};
template <>
template <typename T, typename U>
Value<U> Functor<Value>::fmap(std::function<U(T)> f, Value<T> value) {
return Value<U>(f(value.value()));
}
void test() {
std::function<std::string(int)> fn = [](int x) {
return std::to_string(x);
};
auto result = fmap(fn)(Value(42));
// result.value() == "42"
}
Now I am trying to get it to work with a more complicated type that uses std::tuple or std::variant like in the above example.
template <>
template <typename T, typename U>
Foo<U> Functor<Foo>::fmap(std::function<U(T)> f, Foo<T> value) {
return Foo<U>(std::get<0>(value), f(std::get<1>(value)));
}
void test() {
std::function<std::string(int)> fn = [](int x) {
return std::to_string(x);
};
// This is the desirable syntax but it doesn't build
// fmap(fn)(Foo<int>(42, 7));
// This builds but it's super ugly
fmap(fn).operator()<Foo>(Foo<int>(42, 7));
}
Based on the response by SkepticalEmpiricist below, I am thinking that type aliases may not be the way to go here and instead I will have to introduce small wrapper classes - unless there is an SFINAE approach that would get this working.
This library is mostly a curiosity and a means for me to explore some more advanced template concepts - thanks for the help!
So first attempt before we start digging for some SFINAE based trickery to try circumvent the unavoidable:
Alias templates are never deduced by template argument deduction
We could "deduce" the template arguments for the compiler ourselves like this:
#include <tuple>
template <typename T>
using Foo = std::tuple<int, T>;
template <template <typename ...> class F, typename T, typename ...Ts>
void foo(F<T, std::string, Ts...> bar) {}
void test() {
foo(Foo<std::string>());
}
So now we have it compiling for your foo(Foo<std::string>()); call with Foo being the alias template over std::tuple and, more importantly, foo() is still specialized only for Foo<std::string>.
However, to support usage simultaneously of foo() for both the std::tuple alias template and the wrapper class for example, we still don't have it compiling error-free. As in, if we now comment-out the tuple-flavor Foo and bring back in the wrapper class Foo then calling our rewritten foo() will not compile.
To address the issue, let's give it a try with SFINAE to the rescue and replace the last declaration of foo() with this code:
template <template <typename ...> class F, typename T, typename ...Ts,
typename std::enable_if_t<std::is_same<F<T, Ts...>,
std::tuple<T, Ts...>>::value >* = nullptr>
void foo(F<T, std::string, Ts...> bar) {}
template <template <typename> class F>
void foo(F<std::string> bar) {}
Now you can call foo() for instances of both wrapper class of tuples and alias template for tuples. You could implement in the same fashion for std::variant as well.
With:
template <typename T> using Foo = std::tuple<int, T>;
template <template <typename> class F> void foo(F<std::string> bar) {}
void test() { foo(Foo<std::string>()); }
Foo<std::string> is std::tuple<int, std::string>.
so test is
void test() { foo(std::tuple<int, std::string>()); }
How do you expect compiler deduce from tuple from which alias it come ?
we might have
template <typename T> using Bar = std::tuple<int, std::string>;
template <typename T> using Bar2 = std::tuple<some_trait<T>::type, some_trait<T>::type2>;
// ...
A possible workaround might be:
template <typename T, typename U>
Foo<U> fmap(std::function<U(T)> f, Foo<T> value)
{
return Foo<U>(std::get<0>(value), f(std::get<1>(value)));
}
With calling syntax:
fmap(fn, Foo<int>(42, 7));

C++ template class, template member friend function matching rules

I have a templated class with a templated friend function declaration that is not having its signature matched when stated in a more direct, but seemingly equivalent, expression:
link to example on online compiler
#include <type_traits>
template <typename Sig> class Base;
template <typename R, typename ... Args> class Base<R(Args...)> { };
template <typename Sig, typename T> class Derived;
template <typename Sig> struct remove_membership;
template <typename T, typename R, typename ... Args>
class Derived<R(Args...), T> : public Base<R(Args...)> {
static void bar() { }
// XXX: why are these two not equivalent, and only the 1st version successful?
template <typename T2>
friend auto foo(T2 const &) -> Base<typename
remove_membership<decltype(&std::remove_reference_t<T2>::operator())>::type> *;
template <typename T2>
friend auto foo(T2 const &) -> Base<R(Args...)> *;
};
template <typename F, typename R, typename ... Args>
struct remove_membership<R (F::*)(Args...) const> {
using type = R(Args...);
};
template <typename T>
auto foo(T const &) -> Base<typename
remove_membership<decltype(&std::remove_reference_t<T>::operator())>::type> *
{
using base_param_t = typename remove_membership<
decltype(&std::remove_reference_t<T>::operator())>::type;
Derived<base_param_t, T>::bar();
return nullptr;
}
int main(int, char **) { foo([](){}); } // XXX blows up if verbose friend decl. removed.
Inside member definitions of Derived<R(Args...), T> (for example, in the body of bar()), the types match, adding to my confusion:
static_assert(std::is_same<Base<R(Args...)>, Base<typename
remove_membership<decltype(&std::remove_reference_t<T>::operator())>::type>>::value,
"signature mismatch");
Are there rules around template class template member function (and friend function) delarations and instantiations that make these preceding declarations distinct in some or all circumstances?
template <typename T2>
void foo(T2 const &)
template <typename T2>
auto foo(T2 const &)
-> std::enable_if_t<some_traits<T2>::value>;
Are 2 different overloads. Even if both return void (when valid).
2nd overload uses SFINAE.
(and yes, template functions can differ only by return type contrary to regular functions).
Your version is not identical but similar (&std::remove_reference_t<T>::operator() should be valid)
You can use the simpler template friend function:
template <typename T, typename R, typename ... Args>
class Derived<R(Args...), T> : public Base<R(Args...)> {
static void bar() { }
template <typename T2>
friend auto foo(T2 const &) -> Base<R(Args...)>*;
};
template <typename T>
auto foo(T const &) -> Base<void()>* // friend with Derived<void(), U>
{
using base_param_t = typename remove_membership<
decltype(&std::remove_reference_t<T>::operator())>::type;
Derived<base_param_t, T>::bar();
return nullptr;
}
Demo
but you have then to implement different version of the template foo.
The problem can be reduced to:
template<class T>
struct identity {
using type=T;
};
class X {
int bar();
public:
template<class T>
friend T foo();
};
template<class T>
typename identity<T>::type foo() { return X{}.bar(); }
int main() {
foo<int>(); // error: bar is a private member of X
}
Even though we know identity<T>::type is always T, the compiler doesn't know that and would be wrong to assume so. There could be a specialization of identity<T> somewhere later in the code that resolves to some type other than T.
Therefore when the compiler sees the second declaration of foo it won't assume that it is the same friend foo declared before.

How to create template for this function?

For structs
<template typename T>
struct Foo
{
...
}
<template typename T>
struct Boo
{
...
}
I want to create function that i will call like
DoSomething<Boo<int>>(x);
DoSomething<Foo<float>>(x);
I tried something like this
<template typename T>
<template typename U>
void DoSomething(T<U>& x)
but it doesn't compile. How do I make template for this kind of function?
Thanks
just do:
template <typename T>
struct Foo
{
};
template <typename T>
struct Boo
{
};
template <typename T>
void DoSomething(T& x) // One parameter is enough, compiler will deduce types automatically
{
}
Boo<int> x;
Foo<float> y;
DoSomething(x); // compiler will generate void DoSomething(Boo<int>& x)
DoSomething(y); // compiler will generate void DoSomething(Foo<float>& x)
Your template declaration is wrong,
<template typename T> // invalid syntax
should be:
template <typename T>
You need to use template template parameter if you want to specify both types:
template <template<typename> class T, typename U>
void DoSomething(T<U>& x)
But depending on what you want to achieve, if you don't need to have both types in your function, simply using a single template parameter should work:
template <typename Y>
void DoSomething(T& x)
<template typename T>
void DoSomething(T& x)
{
// do something
}
You have two choices. For the sake of the examples, consider your Foo template struct and this declaration:
Foo<double> v;
Your first choice is
template <typename T>
void DoSomething1(T& x) { /* ... */ }
// ...
DoSomething1(v);
I strongly believe this is what you need.
However, it might not be the case. Perhaps, you really need to call the function on a type of the form T<U> where T is a template class and U is a type. For instance you might want to instantiate T with an int (that is, create T<int> y;) inside the function's body. Then, your second choice is
template <template <typename> class T, typename U>
void DoSomething2(T<U>& x) { T<int> y; /* ... */ }
// ...
DoSomething2(v);
Unfortunately, this might not yet be enough! If you try,
std::vector<double> w;
// ...
DoSomething2(w);
The last line fails to compile. The reason is that std::vector is a template class that take two type parameters and DoSomething2 expects a template class that takes just one. (Of course one can instantiate std::vector with just one argument because the second one has a default value.) The solution is using a C++11 variadic template template parameter:
template <template <typename, typename...> class T, typename U>
void DoSomething3(T<U>&) { T<int> y; /* ... */ }
// ...
DoSomething3(v);
DoSomething3(w);

Applying partially applied template

Having a class like the A, is there a way to apply it to a template like this of B, with T2 set to some type C? But without creating another template class inheriting from A.
template<typename T1, typename T2>
class A
{ };
template<template <typename T1> class T3>
class B
{ };
With C++11 using a template alias works:
template<typename T1, typename T2>
class A
{ };
template<template <typename T1> class T3>
class B
{ };
class C
{ };
template< typename T > using A1 = A< T, C >;
int main()
{
B< A1 > b;
}
without C++11, you are left with what you probably already know:
template< typename T > class A1 : A< T, C > {};
I will propose an alternative solution: do not use template template parameters.
If you write:
template <typename T> struct B {};
Then it can be used with A<int, int> or C<3> or even plain D.
Whilst it is possible to use template template parameters, it is general a bad idea. You should treat the template parameter of a class as an implementation detail and apply the golden rule: do not rely on implementation details.
If you need access to the type, somehow, then use an associated type (aka T::AssociatedType) or a trait (BTraits<T>::AssociatedType).
EDIT: dealing with multiple instantiations of the template template parameter.
Suppose we want to "erase" the template template parameter of such a class:
template <template <typename> class A>
struct Something {
template <typename T>
void doit() { A<T>::doit(); }
};
The C++ standard allocation model is to use an inner rebind structure:
template <typename T>
struct Simple {
template <typename U>
struct rebind { typedef Simple<U> type; };
};
template <typename T0, typename T1>
struct Multi {
template <typename U>
struct rebind { typedef Multi<U, T1> type; };
};
template <typename A>
struct Something {
template <typename T>
void doit() { typedef typename A::rebind<T>::type B; B::doit(); }
};
Note how you can use complex computations in rebind and nothing forces you in blindly passing the type received as parameter.
Whilst another (similar) solution is to ask for a factory (aka, the object passed itself cannot be used but it can build useful objects); for ease of use the C++ containers ask of their allocators that they be both usable in themselves and factories for other types.
Yes, you can do it using C++11's alias template:
template <typename T>
using AA = A<T, C>;
B<AA> b;
Live example

Reducing number of template arguments for class

I have a method and two classes defined like this:
template<template<class X> class T>
void doSomething()
{
T<int> x;
}
template <class T>
class ClassWithOneArg
{
T t;
};
template <class T1, class T2>
class ClassWithTwoArgs
{
T1 t1;
T2 t2;
};
I can now
doSomething<ClassWithOneArg>();
but I cannot
doSomething<ClassWithTwoArgs>();
However, I'd like to pass ClassWithTwoArgs to doSomething, where T2 = double.
The only method I found is to create
template <class T1>
class ClassWithTwoArgs_Child
: public ClassWithTwoArgs<T1, double>
{
};
and then
doSomething<ClassWithTwoArgs_Child>();
This works, but in my concrete case all classes require a constructor argument and thus I have to create a constructor with this argument also in the _Child-class and pass it to the base which I really want to avoid.
Do you have an idea how to do that?
Thanks a lot!
Indirection is a solution. Instead of a template template parameter you pass a "meta function" -- a function that maps one type to another in form of a struct with a nested class template:
struct mf1 {
template<class Arg1>
struct eval {
typedef ClassTemplateWithOneArg<Arg1> type;
};
};
template<class Arg2>
struct mf2 {
template<class Arg1>
struct eval {
typedef ClassTemplateWithTwoArgs<Arg1,Arg2> type;
};
};
template<class MetaFunc>
void do_something()
{
typedef typename MetaFunc::template eval<int>::type clazztype;
clazztype x;
}
void foo() {
do_something<mf1>();
do_something<mf2<double> >();
}
In C++0x this could be reduced to a "template typedef":
template<class Arg1>
using NewClassTemplate = ClassTemplateWithTwoArgs<Arg1,double>;
which allows you to pass NewClassTemplate as a template template argument which also accepts only one template parameter.
There is no generic solution. Your best bet is
template<class T>
void doSomething()
{
T x;
}
template <class T>
class ClassWithOneArg
{
T t;
};
template <class T1, class T2 = double>
class ClassWithTwoArgs
{
T1 t1;
T2 t2;
};
int main(){
doSomething<ClassWithOneArg<int>>();
doSomething<ClassWithTwoArgs<int, double> >();
}
It seems that what you are after is similar to the rebinding of allocators (given an allocator, containers need to be able to produce an allocator for a different type - e.g std::list<int> might need a allocator<list_node<int> > from allocator<int>.
However, the class templates would have to be modified for this.
template<class T>
void doSomething(const T&)
{
typename T::template rebind_1st<int>::type x;
}
template <class T>
class ClassWithOneArg
{
T t;
public:
template <class U>
struct rebind_1st { typedef ClassWithOneArg<U> type; };
};
template <class T1, class T2>
class ClassWithTwoArgs
{
T1 t1;
T2 t2;
public:
template <class U>
struct rebind_1st { typedef ClassWithTwoArgs<U, T2> type; };
};
int main()
{
doSomething(ClassWithOneArg<char>());
doSomething(ClassWithTwoArgs<char, double>() );
}
Assuming you want declare template instantiations of the same class with a different type for the first template parameter, it appears a version of visitor's code is possible that doesn't require modifying original classes.
template <class T, class NewFirstArg>
struct rebind_1st;
template <template <class> class T, class Arg1, class NewFirstArg>
struct rebind_1st<T<Arg1>, NewFirstArg>
{
typedef T<NewFirstArg> type;
};
template <template <class, class> class T, class Arg1, class Arg2, class NewFirstArg>
struct rebind_1st<T<Arg1, Arg2>, NewFirstArg>
{
typedef T<NewFirstArg, Arg2> type;
};
template <class T>
void foo()
{
typename rebind_1st<T, int>::type x;
(void)x;
}
template <class T>
struct One{};
template <class T1, class T2>
struct Two{};
int main()
{
foo<One<char> >();
foo<Two<char, double> >();
}
This works with MSVC:
template<class T>
void doSomething()
{
T x;
}
// class definitions omitted...
void test() {
doSomething<ClassWithOneArg<int> >();
doSomething<ClassWIthTwoArgs<int, double> >();
}
I do not fully understand why you want to define the first parameter of your template template parameter to be int inside of doSomething. Looks like a "template smell" to me, since doSomething has to know a lot about its template template parameter.
Wouldn't it be cleaner to call doSomething the way i proposed? (But obviously i don't know the context of your calls).