C++ Hide template parameters - c++

I don't know if this is possible at all, but I would like to "hide" some template parameters from a given class. Here's what I mean, say I have the following code:
template<class A, int b>
class Foo
{
};
template<template<class,int> class Foo_specialized, class A, int b>
class Bar
{
Foo_specialized<A,b> obj;
};
Now supposed Bar does not need to know about A, but needs to know about b.
Naturally something like this would be perfect (the following is a pseudo code just to illustrate the idea):
template<template<int> class Foo_specialized_by_first_parameter, int b>
class Bar
{
Foo_specialized_by_first_parameter<b> obj;
};
I'm not really sure if that's possible at all, the idea would be to have something like this when instancing Bar:
Bar<Foo<float>, 5> bar_instance;
Of course this does not work because Foo doesn't accept 1 parameter.
Basically I need something like (Foo<float>)<5> to be possible. The closest thing I can think of is currying in haskell.

You may use template typedef:
template <int N>
using Foo_float = Foo<float, N>;
And then, with
template <template<int> class Foo_specialized_by_first_parameter, int b>
class Bar
{
Foo_specialized_by_first_parameter<b> obj;
};
you may do:
Bar<Foo_float, 5> bar_instance;

Assuming for a second that you can change that int to std::integral_constant:
#include <iostream>
#include <string>
#include <map>
template<template<typename...> typename T, typename H>
struct Bind1st
{
template<typename... Arg>
using type = T<H, Arg...>;
};
int main() {
// to bind it
Bind1st< std::map, std::string >::type< std::string > mymap;
mymap[ "a" ] = "b";
}
Naturally, Bar< Bind1st< Foo, float >::type, 5 > should also work.

Related

Derive template arguments from other argument but keep intelli sense

Let's assume I have the following classes:
template<typename A> class Foo { ... };
template<typename A, typename B = Foo<A>> class Bar { ... };
Bar is virtual, and it can be derived with many different arguments for A and B. The template's purpose is to provide intelli-sense for the derivations. I do not want to use interfaces for A and B since they have nothing in common. Also, it would cause a lot of unnecessary casting.
The problem is that I also want to provide various algorithms that use Bar, some generic ones, and some are specialized. Something I tried looks like this:
template<typename A, typename B = Foo<A>, typename BarType = Bar<A, B>>
class Algorithm
{
void doWork(BarType& bar) { ... };
};
What I want to do is pass a derivation from Bar to the Algorithm, and it should automatically detect the arguments A and B. For example:
class BarDerivation : Bar<int, Foo<int>> { ... };
Algorithm<BarDerivation> alg;
This answer provides a solution using type-traits, the problem is that Algorithm would lose the information that BarType is from type Bar.
I'm not certain if what I'm doing is the best approach for what I want to achieve. So is there a solution that solves my problem, or are there better approaches?
Simpler would be to add alias in Foo/Bar:
template<typename A> class Foo { using type = A; };
template<typename A, typename B = Foo<A>> class Bar { using T1 = A; using T2 = B; };
class Derived : Bar<int, Foo<float>> { /*...*/ };
template <typename BarType>
class Algorithm
{
using A = typename BarType::T1;
using B = typename BarType::T2;
void doWork(BarType& bar) { ... };
};

Templates inside templates. Specializing a template class inside a template function

In the following example, I want to get a stl container (either list or unordered_set) using the template function f. I know that the stl container will contain integers.
I tried to use partial template template specialization but it was not working.
How do I achieve what I want?
The code above doesn't compile obviously.
#include <list>
#include <unordered_set>
template <typename T, template C<T>>
C<T> f()
{
C<T> d;
d.insert(1);
return d;
}
int main()
{
auto l = f<int, std::list<int>>();
auto s = f<int, std::unordered_set>();
return 0;
}
Thanks.
You're going to have a problem at least in that std::list doesn't take insert the same way std::unordered_set does. The former requires a position; the latter does not.
That aside, I can make it compile and execute with (don't forget you need to instantiate the template):
template <typename T, typename C>
C f()
{
C d;
d.insert(1);
return d;
}
template std::unordered_set<int> f<int, std::unordered_set<int>>();
But you won't be able to use a list this way.
Is this sort of thing acceptable to you? If not, I think you need to clarify your question more as to what you want.
You can simply create a set of overloaded functions to insert in the container-specific ways you need.
template <typename T>
void f_impl(std::unordered_set<T> & container)
{
container.insert(1);
}
template <typename T>
void f_impl(std::list<T> & container)
{
container.push_back(1);
}
template <typename T, template<class...> class C>
C<T> f()
{
C<T> d;
f_impl(d);
return d;
}
then you can do:
auto c1 = f<int, std::unordered_set>();
auto c2 = f<int, std::list>();
to your heart's delight.
Thanks everyone.
This worked for me. I put it together from the answers you guys posted.
The problem I wanted was much simpler. I wanted to be able to specialize an STL container inside a template function. Obviously, the insert functions are different but I just removed that since I didn't need to insert. I just needed to create the container.
#include <list>
#include <unordered_set>
template <template <class...> class C>
C<int> f()
{
C<int> d;
return d;
}
int main()
{
auto l = f<std::list>();
auto s = f<std::unordered_set>();
return 0;
}

Using a typedefed default type for template parameter

I have a class where I want the template parameter B to have a default type. The problem is that the default type is a complicated expression depending also on the type of A.
The following code illustrates the situation but does obviously not compile, because defaultB type is not know inside the template expression.
template<class A, class B = defaultB>
class Foo{
typedef A::Bar Bar;
typedef Bar::Ex defaultB;
};
Does anybody have an idea how to solve this problem properly?
You could maintain a namespace of defaults like this:
namespace detail {
template <typename A>
using defaultB = typename A::Bar::Ex;
}
template<class A, class B = typename detail::defaultB<A>>
class Foo{
};
This lets you have as complex expressions as you like in your detail namespace without making the Foo declaration ugly.
An alternative to TartanLlama's excellent suggestion is to maintain a dummy type hierarchy to lift up the typedef's into scope:
template<class A>
struct _Foo {
typedef typename A::Bar Bar;
typedef typename Bar::Ex defaultB;
};
template<class A,class B=typename _Foo<A>::defaultB>
struct Foo : _Foo<A> {
};

Add a member for certain template parameters of a template class?

Consider a template class:
template <class First, class Second, class Third, class Fourth>
class MyClass;
What is the right way to add a member function for certain sets of template parameters?
For example, how to add a member f(), when Second is a std::string() ?
Here is the method I've found and I traditionally use:
#include <iostream>
#include <type_traits>
#include <array>
template <class Container>
struct Array
{
Container data;
template <class... Dummy,
class = typename std::enable_if<sizeof...(Dummy) == 0>::type,
class = typename std::enable_if<
std::tuple_size<
typename std::conditional<sizeof...(Dummy),
Container,
Container
>::type
>::value == 1
>::type
>
inline typename Container::value_type& value(Dummy...)
{return data[0];}
};
int main()
{
Array<std::array<double, 0>> array0; // Does not have the value() member
Array<std::array<double, 1>> array1; // Have the value() member
Array<std::array<double, 2>> array2; // Does not have the value() member
Array<std::array<double, 3>> array3; // Does not have the value() member
}
It works well, but it's more a metaprogramming trick than a clean/standard way to do it.
You may use inheritance and specialization.
Something like:
template <typename T> struct Helper2 {};
template <> struct Helper2<std::string>
{
void f() {};
};
template <class First, class Second, class Third, class Fourth>
struct MyClass : public Helper2<Second>
{
// Normal code.
};
int main()
{
MyClass<std::string, int, std::string, std::string> c1;
MyClass<int, std::string, int, int> c2;
//c1.f(); // this is an error
c2.f(); // this works
return 0;
}
I don't quite get the purpose of Dummy in your declaration. It can be done with two defaulted template parameters that are not used at all in function parameter list:
#include <type_traits>
#include <string>
template <class First> // arguments ommited for brevity
struct MyClass {
template<
typename U = First,
typename = typename std::enable_if< std::is_same<U, std::string>::value >::type
>
void f() {}
};
int main()
{
MyClass<int> c1;
MyClass<std::string> c2;
// this is an error
// c1.f();
c2.f(); // this works
}
Live example.
Note that it's possible to cheat: c1.f<std::string>(); will still work.
In C++1y concepts TS we have requires clauses that may let you do this easily. See http://isocpp.org/files/papers/n3929.pdf -- I may be wrong, however.
Outside of C++1y, your technique makes your program ill-formed with no diagnosis required, as all function templates must have at least one valid specialization. As it happens, this is a very rarely enforced requirement, because solving for "there are no valid specializations" in the general case involves solving the halting problem. Despite this, it is the programmers responsibility to ensure that all template functions have at least one valid set of template arguments.
The way I have found that is strictly legal for a zero-argument function in C++11 is to use CRTP based class specialization that eliminates the method in a specialization of the CRTP base.
Another way is to create a private, inaccessible type, and make that the only way to create a legal specialization in the case where you want to disable it. Then privately inside the class you can cheat, but outside you cannot cheat.

C++: renaming templated class

I'm looking for some code to make it work
template <typename T, int a, int b>
class first
{ //not so important
};
main()
{
first<double,1,2> sth;
second<double> sth2;
}
Sth2 is the same type as sth, but has default parameters (for example)
I do know I need some typedef. I tried
template <typename T>
struct help
{
typedef first<T,1,1> second;
};
but it works only with additional :: (help< double>::second) and i just want to change it for second< double>
Thank you for any ideas :)
You should just be able to define
template <typename T, int a=1, int b=2> class first
and then
first<double> sth2;
But if you really want two classes
template <typename T> class second : public first<T,1,1>
Should get you somewhere.
What about using default parameters? Otherwise igor might be right with C++11