Templates inside templates. Specializing a template class inside a template function - c++

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

Related

Template class with iterator to a STL container

I want to create a template class which has an iterator of a STL container as a member. That is how far I got:
#include <iostream>
#include <vector>
using namespace std;
template<typename Element, template <class> class StdLibContainer>
struct ClassHoldingAnIteratorToAStandardContainer
{
ClassHoldingAnIteratorToAStandardContainer(){}
typename StdLibContainer<Element*>::iterator std_lib_iterator;
};
int main()
{
vector<int> vec{1,2,3};
ClassHoldingAnIteratorToAStandardContainer<int,vector<int>> holding_iterator_to_vec;
//DOES NOT WORK, compiler says: expected a class template, got ‘std::vector<int>’
return 0;
}
Could you explain the syntax template <typename> class StdLibContainer?
I found it somewhere on stackoverflow. BUt I don't understand it.
How can I create an instance of ClassHoldingAnIteratorToAStandardContainer ? All my attempts failed so far. The compiler always gives the error message: `expected a class template, got ‘std::vector’
In the above example i want to assign holding_iterator_to_vec vec.begin().
template <typename> class is the same as template <class> class. Originally, when templates were introduced, they allowed two equivalent forms:
template<class T> struct Foo {};
// or
template<typename T> struct Foo {};
Do not ask me why! However, the same was not true for template template parameters:
template <template <class> typename T> struct Foo {};
was the only allowed syntax. Apparently, people were unhappy about it, so the syntax was relaxed.
As for your second question, std::vector takes at least two template arguments, data type and allocator. This is why a single argument template doesn't cut it before C++17. After C++17, it would work.
To make it universal, use
template<template <class...> class Container> struct Foo{};
Unless you really need to know the type of the container, I would strongly recommend to keep your ClassHoldingAnIteratorToAStandardContainer independent of the concrete container type. If you just need the iterator, this is simpler and sufficient:
template<typename iterator>
struct iterator_wrapper {
iterator iter;
};
Thats the minimum you need to have an iterator as member :).
I dont really know what you want to use the iterator for, so just for the sake of an example lets add methods that actually use the iterator....
#include <iterator>
#include <vector>
#include <iostream>
template<typename iterator>
struct iterator_wrapper {
using value_type = typename std::iterator_traits<iterator>::value_type;
iterator iter;
bool operator!=(const iterator& other) { return iter != other;}
iterator_wrapper& operator++(){
++iter;
return *this;
}
const value_type& operator*() { return *iter; }
};
template <typename iterator>
iterator_wrapper<iterator> wrap_iterator(iterator it) {
return {it};
}
int main() {
std::vector<int> vec{1,2,3};
auto it = wrap_iterator(vec.begin());
for (;it != vec.end();++it) std::cout << *it;
}
Also there is a problem in your code.
typename StdLibContainer<Element*>::iterator
is for containers of pointers while in main you have ints. If you want to infer the iterator type from the container type then you can do it for example like this:
template <typename container,
typename iterator = typename container::iterator>
iterator_wrapper<iterator> wrap_begin(container& c) {
return {c.begin()};
}
which makes creating an iterator_wrapper as simple as
auto x = wrap_begin(vec);
Note that this answer applies to C++11, in newer standards there are deduction guides that make such make_x methods more or less superfluous afaik.

C++ template - using "std::is_same_v" instead of specializing and avoid compilation error?

I'm new to templates and I'm trying to use them in order to avoid duplicating functions that are very much alike.
In the example below, I made a simple and small working example showing my issue.
In particular, I have two struct ("solo" and "duo"). Those struct's have a common member (a) and one of them has a specific member (b).
Then I have a template function that can take either struct and print the member a... and I wanted it to be able to print member b only if the struct type is "duo".
The way I did (using std::is_same_v) it doesn't compile. I read that one can use specialization to do so, however I was wondering if there is not a more elegant way? Because then I have the feeling to loose the advantage of templates... but probably I don't get the power of templates yet and how/for what to use them.
Thank you very much for your help!
#include <iostream>
#include <string>
#include <type_traits>
struct solo{
int a;
};
struct duo : solo{
int b;
};
template<class T>
void function(T test){
std::cout<< std::to_string(test.a);
if(std::is_same<T, duo>::value) std::cout<< std::to_string(test.b);
}
int main()
{
solo testS;
testS.a = 1;
function(testS);
}
To answer your question about templates (although in this particular application, it is not the right solution, for many reasons):
The reason it doesn't work as you wrote it is that template instantiation happens at compile-time, and the only thing happening then is that the value of std::is_same is computed for the template argument. Thus, in the code for function<solo> the line
if(std::is_same<T, duo>::value) std::cout<< std::to_string(test.b);
would be like
if(false) std::cout<< std::to_string(test.b);
which doesn't compile as there is no member b in test.
To make it work, you need two templates and use SFINAE to select the correct one when instantiating the template (and as function templates cannot be partially specialized, you need to write it something like the following, which is really a silly way of writing two overloads. Or you can fully specialize the template, but then you wouldn't use if_same).
template<class T>
typename std::enable_if<!std::is_same<T, duo>::value, void>::type function(T test){
std::cout<< std::to_string(test.a);
}
template<class T>
typename std::enable_if<std::is_same<T, duo>::value, void>::type function(T test){
std::cout<< std::to_string(test.a);
std::cout<< std::to_string(test.b);
}
Further, note that is_same looks at the static type of the variable, so if you have a solo& to a duo object, it would still choose the solo overload.
A somewhat less silly use of templates is to write a function template that can handle any type that has a member int b.
This uses a helper metafunction (a struct, so we can use partial specialization):
template <class T, class = int>
struct has_member_b : std::false_type {};
template <class T>
struct has_member_b<T, decltype(std::declval<T>().b)> : std::true_type {};
template<class T>
typename std::enable_if<has_member_b<T>::value, void>::type function(T test){
std::cout<< std::to_string(test.a);
std::cout<< std::to_string(test.b);
}
template<class T>
typename std::enable_if<!has_member_b<T>::value, void>::type function(T test) {
std::cout<< std::to_string(test.a);
}
(Do note that both versions assume there to be a member a, if not it will not compile)
With the introduction of constexpr if(cond) in C++17 you can achieve your goal. constexpr if(cond) gets evaluated at compile time, hence you can choose what you want to do depending the type of the parameter. Following snippet provides an illustration.
#include <iostream>
#include <string>
#include <type_traits>
struct solo{
int a;
};
struct duo : solo{
int b;
};
template<class T>
void function(T test){
if constexpr (std::is_same<T, duo>::value)
std::cout<< std::to_string(test.b)<<"\n";
else if constexpr (std::is_same<T, solo>::value)
std::cout<< std::to_string(test.a)<<"\n";
}
int main()
{
solo test1;
test1.a = 1;
duo test2;
test2.b = 2;
function(test1);
function(test2);
}
You don't need template for this since duo extends solo. Simply call function(solo) from function(duo):
void function(solo test) {
std::cout << std::to_string(test.a);
}
void function(duo test) {
function((solo) test);
std::cout << std::to_string(test.b);
}

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.

A recursive template type for a container / typename forwarding

Is there any way to get a recursive template type? I have a container for which I want to specify an underlying storage strategy. The inner template must however use the outer template's type, so it causes a loop in the type definition -- which isn't possible to specify.
About what I want:
template<typename C>
struct inner {
C * object[16];
};
template<typename T, typename Inner>
struct container {
T value;
Inner<container> holder;
};
C++11 solutions are fine (though I'm still on gcc 4.6.3).
You need to tell the compiler that Inner is a templated class:
template<typename T, template<typename> class Inner>
struct container {
T value;
Inner<container> holder;
};
I'm not sure why you're adding the Inner type template parameter, since you're defining holder to be a type based on Container and inner, both of which are available at the point you're declaring holder.
Are you planning on using any type other than struct inner as a template param to Container? If not, the following simplified code compiled and ran for me in VS2010 :
#include <vector>
#include <stdio.h>
template <typename C>
struct inner{
C * objects[16];
bool hasobj;
inner():hasobj(false){}
};
template <typename T>
class Container {
inner<Container> holder;
T value;
public:
Container(const T& valueP){
value = valueP;
}
void AddChild(Container* rhs){
holder.objects[0] = rhs; //Always using first location, just for example
holder.hasobj = true;
}
void PrintStuff()const{
if(holder.hasobj){
holder.objects[0]->PrintStuff();
}
printf("VAL IS %d\n", value);
}
};
int main(){
Container<int> c(10);
Container<int> c1(20);
c1.AddChild(&c);
c1.PrintStuff();
}
Basically, this is assuming that the container is always defining holder in terms of inner, which helps get rid of the extra template parameter, when defining Container. Hope this helps :)
arun

simple C++ templates suited for STL Containers

I need a template like this, which work perfectly
template <typename container> void mySuperTempalte (const container myCont)
{
//do something here
}
then i want to specialize the above template for std::string so i came up with
template <typename container> void mySuperTempalte (const container<std::string> myCont)
{
//check type of container
//do something here
}
which doesnt't work, and throws an error. I would like to make the second example work and then IF possible i would like to add some code in the template to check if a std::vector/std::deque/std::list was used, to do something differently in each case.
So i used templates because 99% of the code is the same for both vectors and deques etc.
To specialize:
template<> void mySuperTempalte<std:string>(const std::string myCont)
{
//check type of container
//do something here
}
To specialize for vector:
template<typename C> void mySuperTempalte (std::vector<C> myCont)
{
//check type of container
//do something here
}
To specialize for deque:
template<typename C> void mySuperTempalte (std::deque<C> myCont)
{
//check type of container
//do something here
}
Have you tried a template typename parameter? The syntax is a bit weird because it emulates the syntax used to declare such a container. There's a good InformIT article explaining this in more detail.
template <template <typename> class Container>
void mySuperTemplate(Container<std::string> const& cont) {
}
Notice that you also should declare the argument as a reference!
By the way: this comment
//check type of container
is a dead giveaway that you're doing something wrong. You do not want to check the type of the container. User more sophisticated overloading instead, as shown in sep's answer.
If I am understanding your problem correctly you have an algorithm that will work for STL containers vector, deque etc but are trying to write a template specialisation for string. If this is the case then you can write the generalised templated method that you defined in your question:-
template<typename container> void mySuperTempalte( const container &myCont )
{
// Implement STL container code
}
Then for your string specialisation you declare:-
template<> void mySuperTempalte( const container<std::string> &myCont )
{
// Implement the string code
}
For any other specialisation just change the type declaration for myCont. If you really need to do this for the vector and deque containers then make the template parameter the parameter for the type in that container rather than the container itself as Sep suggested.
template<typename C> void mySuperTempalte( const std::vector<C> &myCont)
{
// check type of container
// do something here
}
It's worth trying to avoid this by making your first implementation work with all STL containers to make your life easier, then you only need the specialisation for the string class. Even consider converting your string to a vector to avoid the specialisation all together.
On a side note, I've changed the container parameter to a const reference, I assume this is what you want, as you declare the object const anyway, this way you avoid a copy.
The answers so far seem helpful, but I think I'd use a different construct. I expect all containers to define value_type, just like the STL containers do. Therefore, I can write
inline template <typename C> void mySuperTemplate (C const& myCont)
{
mySuperTemplateImpl<C, typename C::value_type>(myCont);
}
In general, it's easier to act on a parameter that you've extracted explicitly.
#sep
'Simple' solution
The answer posted by 'sep' is pretty good, probably good enough for 99% of app developers, but could use some improvement if it's part of a library interface, to repeat:
To specialize for vector:
template<typename C> void mySuperTempalte (std::vector<C> myCont)
{
//check type of container
//do something here
}
This will work provided the caller isn't using std::vector. If this works well enough for you, to specialize for vector, list, etc, then stop here and just use that.
More complete solution
First, note that you can't partially specialize function templates -- you can create overloads. And if two or more of them match to the same degree, you will get "ambigous overload" errors. So we need to make exactly one match in every case you want to support.
One technique for doing this is using the enable_if technique -- enable_if allows you to selectively take function template overloads out of the possible match list using an obscure language rule... basically, if some boolean expression is false, the overload becomes 'invisible'. Look up SFINAE for more info if you're curious.
Example. This code can be compiled from the command line with MinGW (g++ parameterize.cpp) or VC9 (cl /EHsc parameterize.cpp) without error:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template <bool B, class T> struct enable_if {};
template <class T> struct enable_if<true, T> { typedef T type; };
template <class T, class U> struct is_same { enum { value = false }; };
template <class T> struct is_same<T,T> { enum { value = true }; };
namespace detail{
// our special function, not for strings
// use ... to make it the least-prefered overload
template <class Container>
void SpecialFunction_(const Container& c, ...){
cout << "invoked SpecialFunction() default\n";
}
// our special function, first overload:
template <class Container>
// enable only if it is a container of mutable strings
typename enable_if<
is_same<typename Container::value_type, string>::value,
void
>::type
SpecialFunction_(const Container& c, void*){
cout << "invoked SpecialFunction() for strings\n";
}
}
// wrapper function
template <class Container>
void SpecialFunction(const Container& c){
detail::SpecialFunction_(c, 0);
}
int main(){
vector<int> vi;
cout << "calling with vector<int>\n";
SpecialFunction(vi);
vector<string> vs;
cout << "\ncalling with vector<string>\n";
SpecialFunction(vs);
}
Output:
d:\scratch>parameterize.exe calling
with vector<int> invoked
SpecialFunction() default
calling with vector<string> invoked
SpecialFunction() for strings
d:\scratch>
Whether it is a good design or not is left for further discussion. Anyway, you can detect the type of container using partial template specializations. In particular:
enum container_types
{
unknown,
list_container,
vector_container
};
template <typename T>
struct detect_container_
{
enum { type = unknown };
};
template <typename V>
struct detect_container_< std::vector<V> > // specialization
{
enum { type = vector_container };
};
template <typename V>
struct detect_container_< std::list<V> >
{
enum { type = list_container };
};
// Helper function to ease usage
template <typename T>
container_types detect_container( T const & )
{
return static_cast<container_types>( detect_container_<T>::type );
}
int main()
{
std::vector<int> v;
assert( detect_container( v ) == vector_container );
}