How to specify constructor within three template arguments - c++

I have to define the priority_queue class in the main.
int main(){
...
pri_queue_t<string, vector_t<string>, cmp> q3;
...
}
Therefore, I tried to make a header file like below.
template<typename T, class V, class O> //the last argument is alphabet 'O'
class pri_queue_t{
public:
pri_queue_t(); //constructor
....
}
template<typename T, class V, class O>
pri_queue_t<T, V, O>::pri_queue_t(){} //body of constructor**
The error code is
/home/mys/Desktop/stl_project/2_adp/main.cc: In function ‘int main()’:
/home/mys/Desktop/stl_project/2_adp/main.cc:147:43: error: ‘cmp’ was
not declared in this scope; did you mean ‘bcmp’?
147 | pri_queue_t<string, vector_t<string>, cmp> q3;
| ^~~
| bcmp
/home/mys/Desktop/stl_project/2_adp/main.cc:147:46: error: template
argument 3 is invalid
147 | pri_queue_t<string, vector_t<string>, cmp> q3;
I meant the cmp as option that makes pri-queue ascending. How to make the right constructor? And How to define the cmp?

Priority queue is:
template<
class T,
class Container = std::vector<T>,
class Compare = std::less<typename Container::value_type>
> class priority_queue;
Note the default for the thrid parameter. If you do not know what else to put there then the default is probably fine:
template<typename T, class V>
class pri_queue_t{
public:
pri_queue_t(); //constructor
....
}
template<typename T, class V>
pri_queue_t<T, V>::pri_queue_t(){} //body of constructor**
I am a bit confused by //the last argument is alphabet 'O', because the third parameter for priority_queue is a comparator, not an "alphabet". Anyhow, then in main:
int main(){
pri_queue_t<string, vector_t<string>> q3;
}
If vector_t is std::vector, you could also get rid of the second parameter.
Alternatively you can use the defaults from the priority_queue:
#include <queue>
template <typename T>
struct prio_queue_defaults {
using container_type = typename std::priority_queue<T>::container_type;
using value_compare = typename std::priority_queue<T>::value_compare;
};
template <typename T,
typename container = typename prio_queue_defaults<T>::container_type,
typename compare = typename prio_queue_defaults<T>::value_compare>
struct my_prio_queue {
std::priority_queue<T,container,compare> x;
};
int main() {
my_prio_queue<int> y;
my_prio_queue<int,std::vector<int>> z;
}
Note that there is no need to write a constructor for this simple example, because the compiler generated one already does the right thing.
(The trait prio_queue_defaults is not really needed here and it also does not help to write less code, I just used it to have meaningful names.)

Related

Passing values to inner class via template arguments C++

Trying to pass the value to nested class via template agrument,and have some confusion:
template<typename A,typename B>
class outter{
int a;
T* p;
////...////
template<typename N=int> class inner;
inner do_something(){
return inner<a>(p)
}
}
template<typename T,typename A, typename N=int>
class outter<T,A>::inner<N>{
sz=N;
}
Task is to create an iterator for vector with range control.
For now im stuck in inner class template declaration and passing arguments. Please, i need advance if that possible. Thanks!
For the inner class, you have template <typename N>, which means that your N is a type, not a value, hence, you cannot assign it to a value.
To solve your issue, try having template <int N> class inner; and also fix the same way at the bottom template<typename T, typename A, int N>
Edit
Just noticed, that at the bottom you have the inner class definition. What you want this sz to be? is it a value or type? In case you want this to be a value, you should write
template<typename T,typename A, int N> // this last int determines also the type to be used down below v
class outter<T,A>::inner<N>{
int sz=N; // this int comes from the upper side ^
}
If you want the sz to be a type defining the sizes within the inner class, then keep the upper and bottom parts to be <..., typename N = int> and put using before sz=N;
template<typename T,typename A, typename N=int>
class outter<T,A>::inner<N>{
using sz=N;
}
If you want to have N type and value be specified through templates, please follow this example:
template </*outer template params*/>
class outer {
template <typename SIZE_TYPE, SIZE_TYPE VALUE = SIZE_TYPE()>
class inner;
};
template </*outer template params*/, typename SIZE_TYPE, SIZE_TYPE VALUE = SIZE_TYPE()>
class outer</*params*/>::inner<SIZE_TYPE, VALUE> {
using size_type = SIZE_TYPE;
size_type my_value = VALUE;
}
Edit 2
In case you want to understand what happens here, please read more about the template instantiation.

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.

Is it possible to access a c++ template template constant parameter?

I want to do something like this:
template<template<int d, class>
class container,
int dim = d, typename content_data_type>
class MyClass {
};
My Compiler tells me that this is not possible because "d" is not defined outside of:
template<int d, class> class container
Is there maybe another way of doing this ?
Thanks in advance for any help on this topic.
UPDATE:
# Rook: i want to access the "dim" and "content_data_type" parameters later on in a specialization
e.g.
General class:
template<template<int d, class>
class container>
class MyClass {
};
Spec. class:
template<>
class MyClass<vec> {
vec c; // Error: vec needs template parameters
};
This gave me an error because i used my template class "vec" whitout template parameters, i expected the compiler to deduce the template parameters, e.g. when i use
MyClass<vec<3, float> >
then variable "c" should have the type
vec<3, float>
Because this didn't work, I thought i can create two excplicit template paramters "dim" and "content_data_type" which i can access in the specialization class like this:
template<template<int d, class t>
class container,
int dim = d, typename content_data_type = t>
class MyClass<vec> {
vec<dim, content_data_type> c;
};
... and sorry again for not being specific enough with the initial question :)
I don't think what you're doing makes sense, so the answer is "no".
The template parameter container is a class template, not a class. When MyClass is instantiated, its argument is the whole template, not just one instantiation of it. So it's not possible to default the dimension of MyClass to "the dimension of container", because container doesn't have values for its own template parameters. Your class MyClass can create and use one or more instantiations of container with different values of d, but it isn't given any one of them in particular, it's given the template.
By analogy, suppose you pass a pointer-to-function f as a parameter to a function g. You can't then use "the arguments passed to f" in the definition of g. The function g can call f one or more times with different arguments, but it isn't given any one call in particular, it's given the function.
From your update:
e.g. when i use MyClass<vec<3, float> >
You don't use MyClass<vec<3, float> >, there's no such thing. As I say, MyClass takes a template not a class. vec is a template, vec<3, float> is a class. It sounds like maybe you don't need a template as a template parameter at all.
normally the container would expose the dim member, so this would work:
template< template< int, class> class container, int dim, class content_data_type >
class MyClass
{
public:
typedef typename container< dim, content_data_type > container_type;
static const int dim = container_type::dim;
};
template< int d, class >
class acontainer
{
public:
static const int dim = d;
};
MyClass< acontainer, 2, sometype > x;
std::cout << "container size " << x.dim << std::endl;
Below is a workaround, you have to define the two arguments as a type and a static exposed by the container class though (see for example boost::array)
#include <iostream>
template <int d, class T>
struct container
{
typedef T value_type;
static const int static_size = d;
};
template<typename cont, int d = cont::static_size, class T = typename cont::value_type>
struct A
{
static const int dimension = d;
};
int main(void)
{
A<container<10, int> > a;
std::cout << a.dimension << std::endl;
}

Can you help me understand this C++ template code?

Hya,
Can anyone please tell me how this thing is working?
template <typename T,
template <typename ELEM> class CONT = std::deque >
class Stack {
private:
CONT<T> elems; // elements
public:
void push(T const&); // push element
void pop(); // pop element
T top() const; // return top element
bool empty() const { // return whether the stack is empty
return elems.empty();
}
};
What i don't understand is this :
template class V or say this "template class CONT = std::deque"
i visualize this as
template <class>
class CONT = std::deque // here CONT is templatized class declaration.
but what pesters me is , how can we assign something to class name CONT , rather than writing its definition (which i've done till this time):
template <class>
class CONT{
//def
}
one more thing :
template <class> // why its only class written in angle bracket there should be also be name
like : template<class ty>
Thanks a lot , any help is very appreciated)
What i don't understand is this : template class V
There is no such line in your question, so I can't help with that.
template< template <typename ELEM> class CONT = std::deque >
class Stack
This is a declaration of a template template parameter. You pass a template into the Stack template, and then Stack can use it internally.
The = std::deque part is a default value, in case you leave the CONT parameter unspecified. (std::deque is a predefined template.)
However, this will not work, because std::deque takes two arguments. This will work:
template< template <typename ELEM, typename ALLOC> class CONT = std::deque >
class Stack
However ELEM and ALLOC do not actually name anything; they exist merely to clarify what the parameter list of the required template is. So, you can omit them:
template< template <typename, typename> class CONT = std::deque >
class Stack
It's not an object assignment. It's just syntax in a template specifier to specify what the default type argument should be if one is not provided. It's not a definition for that type.

Default values in templates with template arguments ( C++ )

Assume I have a template (called ExampleTemplate) that takes two arguments: a container type (e.g. list, vector) and a contained type (e.g. float, bool, etc). Since containers are in fact templates, this template has a template param. This is what I had to write:
#include <vector>
#include <list>
using namespace std;
template < template <class,class> class C, typename T>
class ExampleTemplate {
C<T,allocator<T> > items;
public:
....
};
main()
{
ExampleTemplate<list,int> a;
ExampleTemplate<vector,float> b;
}
You may ask what is the "allocator" thing about. Well, Initially, I tried the obvious thing...
template < template <class> class C, typename T>
class ExampleTemplate {
C<T> items;
};
...but I unfortunately found out that the default argument of the allocator...
vector<T, Alloc>
list<T, Alloc>
etc
...had to be explicitely "reserved" in the template declaration.
This, as you can see, makes the code uglier, and forces me to reproduce the default values of the template arguments (in this case, the allocator).
Which is BAD.
EDIT: The question is not about the specific problem of containers - it is about "Default values in templates with template arguments", and the above is just an example. Answers depending on the knowledge that STL containers have a "::value_type" are not what I am after. Think of the generic problem: if I need to use a template argument C in a template ExampleTemplate, then in the body of ExampleTemplate, do I have to reproduce the default arguments of C when I use it? If I have to, doesn't that introduce unnecessary repetition and other problems (in this case, where C is an STL container, portability issues - e.g. "allocator" )?
Perhaps you'd prefer this:
#include <vector>
#include <list>
using namespace std;
template <class Container>
class ForExamplePurposes {
typedef typename Container::value_type T;
Container items;
public:
};
int main()
{
ForExamplePurposes< list<int> > a;
ForExamplePurposes< vector<float> > b;
}
This uses "static duck typing". It is also a bit more flexible as it doesn't force the Container type to support STL's Allocator concept.
Perhaps using the type traits idiom can give you a way out:
#include <vector>
#include <list>
using namespace std;
struct MyFunkyContainer
{
typedef int funky_type;
// ... rest of custom container declaration
};
// General case assumes STL-compatible container
template <class Container>
struct ValueTypeOf
{
typedef typename Container::value_type type;
};
// Specialization for MyFunkyContainer
template <>
struct ValueTypeOf<MyFunkyContainer>
{
typedef MyFunkyContainer::funky_type type;
};
template <class Container>
class ForExamplePurposes {
typedef typename ValueTypeOf<Container>::type T;
Container items;
public:
};
int main()
{
ForExamplePurposes< list<int> > a;
ForExamplePurposes< vector<float> > b;
ForExamplePurposes< MyFunkyContainer > c;
}
Someone who wants to use ForExamplePurposes with a non-STL-compliant container would need to specialize the ValueTypeOf traits class.
I would propose to create adapters.
Your class should be created with the exact level of personalization that is required by the class:
template <template <class> C, template T>
class Example
{
typedef T Type;
typedef C<T> Container;
};
EDIT: attempting to provide more is nice, but doomed to fail, look at the various expansions:
std::vector<T>: std::vector<T, std::allocator<T>>
std::stack<T>: std::stack<T, std::deque<T>>
std::set<T>: std::set<T, std::less<T>, std::allocator<T>>
The second is an adapter, and so does not take an allocator, and the third does not have the same arity. You need therefore to put the onus on the user.
If a user wishes to use it with a type that does not respect the expressed arity, then the simplest way for him is to provide (locally) an adapter:
template <typename T>
using Vector = std::vector<T>; // C++0x
Example<Vector, bool> example;
I am wondering about the use of parameter packs (variadic templates) here... I don't know if declaring C as template <class...> C would do the trick or if the compiler would require a variadic class then.
You have to give the full template signature, including default parameters, if you want to be able to use the template template parameter the usual way.
template <typename T, template <class U, class V = allocator<U> > class C>
class ExampleTemplate {
C<T> items;
public:
....
};
If you want to handle other containers that the one from the STL, you can delegate container construction to a helper.
// Other specialization failed. Instantiate a std::vector.
template <typename T, typename C>
struct make_container_
{
typedef std::vector<T> result;
};
// STL containers
template <typename T, template <class U, class V = allocator<U> > class C>
struct make_container_<T,C>
{
typedef C<T> result;
};
// Other specializations
...
template <typename T, typename C>
class ExampleTemplate {
make_container_<T,C>::result items;
public:
....
};
I think, it is required to reproduce all template parameters, even default. Note, that Standard itself does not use template template parameters for containter adaptors, and prefers to use regular template parameters:
template < class T , class Container = deque <T > > class queue { ... };
template < class T , class Container = vector <T>, class Compare = less < typename Container :: value_type > > class priority_queue { ... };
The following code will allow you to do something like you're asking for. Of course, this won't work with standard containers, since this has to already be part of the template class that's being passed into the template.
/* Allows you to create template classes that allow users to specify only some
* of the default parameters, and some not.
*
* Example:
* template <typename A = use_default, typename B = use_default>
* class foo
* {
* typedef use_default_param<A, int> a_type;
* typedef use_default_param<B, double> b_type;
* ...
* };
*
* foo<use_default, bool> x;
* foo<char, use_default> y;
*/
struct use_default;
template<class param, class default_type>
struct default_param
{
typedef param type;
};
template<class default_type>
struct default_param<use_default, default_type>
{
typedef default_type type;
};
But I don't really think this is what you're looking for. What you're doing with the containers is unlikely to be applicable to arbitrary containers as many of them will have the problem you're having with multiple default parameters with non-obvious types as defaults.
As the question exactly described the problem I had in my code (--I'm using Visual Studio 2015), I figured out an alternative solution which I wanted to share.
The idea is the following: instead of passing a template template parameter to the ExampleTemplate class template, one can also pass a normal typename which contains a type DummyType as dummy parameter, say std::vector<DummyType>.
Then, inside the class, one replace this dummy parameter by something reasonable. For replacement of the typethe following helper classes can be used:
// this is simply the replacement for a normal type:
// it takes a type T, and possibly replaces it with ReplaceByType
template<typename T, typename ReplaceWhatType, typename ReplaceByType>
struct replace_type
{
using type = std::conditional_t<std::is_same<T, ReplaceWhatType>::value, ReplaceByType, T>;
};
// this sets up the recursion, such that replacement also happens
// in contained nested types
// example: in "std::vector<T, allocator<T> >", both T's are replaced
template<template<typename ...> class C, typename ... Args, typename ReplaceWhatType, typename ReplaceByType>
struct replace_type<C<Args ...>, ReplaceWhatType, ReplaceByType>
{
using type = C<typename replace_type<Args, ReplaceWhatType, ReplaceByType>::type ...>;
};
// an alias for convenience
template<typename ... Args>
using replace_type_t = typename replace_type<Args ...>::type;
Note the recursive step in replace_type, which takes care that types nested in other classes are replaced as well -- with this, for example, in std::vector<T, allocator<T> >, both T's are replaced and not only the first one. The same goes for more than one nesting hierarchy.
Next, you can use this in your ExampleTemplate-class,
struct DummyType {};
template <typename C, typename T>
struct ExampleTemplate
{
replace_type_t<C, DummyType, T> items;
};
and call it via
int main()
{
ExampleTemplate<std::vector<DummyType>, float> a;
a.items.push_back(1.0);
//a.items.push_back("Hello"); // prints an error message which shows that DummyType is replaced correctly
ExampleTemplate<std::list<DummyType>, float> b;
b.items.push_back(1.0);
//b.items.push_back("Hello"); // prints an error message which shows that DummyType is replaced correctly
ExampleTemplate<std::map<int, DummyType>, float> c;
c.items[0]=1.0;
//c.items[0]="Hello"; // prints an error message which shows that DummyType is replaced correctly
}
DEMO
Beside the not-that-nice syntac, this has the advantage that
It works with any number of default template parameters -- for instance, consider the case with std::map in the example.
There is no need to explicitly specify any default template parameters whatsoever.
It can be easily extended to more dummy parameters (whereas then it probably should not be called by users ...).
By the way: Instead of the dummy type you can also use the std::placeholder's ... just realized that it might be a bit nicer.