Nested template C++ - c++

I have a template class of the form:
template<typename ContainerType>
class ConfIntParamStat {
public:
typedef typename ContainerType::Type Type;
...
private:
void sample(int iteration) {...}
}
I would like to create a specific version of the function sample for the case when ContainerType is a Vector. Where Vector itself is a template class, but I do not know which type of values this Vector holds.
My intuition was to create this in the header file:
template<typename Type>
ConfIntParamStat<Vector<Type> >::sample(int iteration) {
...
}
But it does not compile, and the error from clang is:
error: nested name specifier 'ConfIntParamStat<Vector<Type> >::' for declaration does not refer into a class, class template or class template partial specialization
Is it possible using another syntax ?

If you didnt want to specialize the template and were looking for a member only specialization try the following
#include <iostream>
#include <vector>
using namespace std;
template <typename ContainerType>
class Something {
public:
void do_something(int);
template <typename Which>
struct do_something_implementation {
void operator()() {
cout << "general implementation" << endl;
}
};
template <typename Which>
struct do_something_implementation<vector<Which>> {
void operator()() {
cout << "specialized implementation for vectors" << endl;
}
};
};
template <typename ContainerType>
void Something<ContainerType>::do_something(int) {
do_something_implementation<ContainerType>{}();
}
int main() {
Something<double> something;
something.do_something(1);
return 0;
}
If your intent is to specialize a function, I would just overload the function like so
#include <iostream>
#include <vector>
using namespace std;
template <typename ContainerType>
class Something {
public:
void do_something(int);
template <typename Type>
void do_something(const vector<Type>&);
};
template <typename ContainerType>
void Something<ContainerType>::do_something(int) {
cout << "Called the general method for do_something" << endl;
}
template <typename ContainerType>
template <typename Type>
void Something<ContainerType>::do_something(const vector<Type>&) {
cout << "Called the specialised method" << endl;
}
int main() {
vector<int> vec{1, 2, 3};
Something<double> something;
something.do_something(1);
something.do_something(vec);
return 0;
}
This is mostly why full/explicit function template specializations are not required. Overloading allows for almost the same effects!
Note This is a great article related to your question! http://www.gotw.ca/publications/mill17.htm

You could make use of the overloading mechanism and tag dispatch:
#include <vector>
template <class T>
struct Tag { };
template<typename ContainerType>
class ConfIntParamStat {
public:
typedef typename ContainerType::value_type Type;
//...
// private:
void sample(int iteration) {
sample_impl(Tag<ContainerType>(), iteration);
}
template <class T>
void sample_impl(Tag<std::vector<T> >, int iteration) {
//if vector
}
template <class T>
void sample_impl(Tag<T>, int iteration) {
//if not a vector
}
};
int main() {
ConfIntParamStat<std::vector<int> > cips;
cips.sample(1);
}
As skypjack mentioned this approach has a little draw when using const. If you are not using c++11 (I suspect you dont because you use > > syntax for nested templates) you could workaround this as follows:
#include <iostream>
#include <vector>
template <class T>
struct Tag { };
template <class T>
struct Decay {
typedef T Type;
};
template <class T>
struct Decay<const T> {
typedef T Type;
};
template<typename ContainerType>
class ConfIntParamStat {
public:
typedef typename ContainerType::value_type Type;
//...
// private:
void sample(int iteration) {
sample_impl(Tag<typename Decay<ContainerType>::Type>(), iteration);
}
template <class T>
void sample_impl(Tag<std::vector<T> >, int iteration) {
std::cout << "vector specialization" << std::endl;
}
template <class T>
void sample_impl(Tag<T>, int iteration) {
std::cout << "general" << std::endl;
}
};
int main() {
ConfIntParamStat<const std::vector<int> > cips;
cips.sample(1);
}

Another way to approach this is composition.
The act of adding a sample can be thought of as a component of the implementation of the class. If we remove the implementation of adding a sample into this template class, we can then partially specialise only this discrete component.
For example:
#include <vector>
//
// default implementation of the sample component
//
template<class Outer>
struct implements_sample
{
using sample_implementation = implements_sample;
// implements one function
void sample(int iteration) {
// default actions
auto self = static_cast<Outer*>(this);
// do something with self
// e.g. self->_samples.insert(self->_samples.end(), iteration);
}
};
// refactor the container to be composed of component(s)
template<typename ContainerType>
class ConfIntParamStat
: private implements_sample<ConfIntParamStat<ContainerType>>
{
using this_class = ConfIntParamStat<ContainerType>;
public:
// I have added a public interface
void activate_sample(int i) { sample(i); }
// here we give the components rights over this class
private:
friend implements_sample<this_class>;
using this_class::sample_implementation::sample;
ContainerType _samples;
};
//
// now specialise the sample function component for std::vector
//
template<class T, class A>
struct implements_sample<ConfIntParamStat<std::vector<T, A>>>
{
using sample_implementation = implements_sample;
void sample(int iteration) {
auto self = static_cast<ConfIntParamStat<std::vector<T, A>>*>(this);
// do something with self
self->_samples.push_back(iteration);
}
};
int main()
{
ConfIntParamStat< std::vector<int> > cip;
cip.activate_sample(1);
cip.activate_sample(2);
}

Related

Template member function specialization in a template class

I have a template class and a member function print() to print the data.
template<typename T>
class A
{
public:
T data;
void print(void)
{
std::cout << data << std::endl;
}
// other functions ...
};
Then, I want to either print scalar data or vector data, so I give a specialized definition and get a compiler error.
template<typename T>
void A<std::vector<T>>::print(void) // template argument list error
{
for (const auto& d : data)
{
std::cout << d << std::endl;
}
}
Question: Why does this member function specialization get an error? What is the correct way to define a print function for a vector?
Solution 1: I have tested the following definition.
template<typename T>
class A<std::vector<T>>
{
public:
std::vector<T> data;
void print(void) { // OK
// ...
}
}
This one worked, but I have to copy the other member functions into this specialized class.
EDIT:
Solution 2: To prevent copy all the other member functions, I define a base class containing the common member functions and inherit from the base class:
template<typename T>
class Base
{
public:
T data;
// other functions ...
};
template<typename T>
class A : public Base<T>
{
public:
void print(void)
{
std::cout << this->data << std::endl;
}
};
template<typename T>
class A<std::vector<T>> : public Base<std::vector<T>>
{
public:
void print(void)
{
for (const auto& d : this->data)
{
std::cout << d << std::endl;
}
}
};
This solution works well. Are there some better or more conventional solutions?
Why does this member function specialization get error?
When you instantiate the template class A for example A<std::vector<int>>, the template parameter T is equal to std::vector<int>, not std::vector<T>, and this a specialization case of the function. Unfortunately this can not be done with member functions as mentioned in the comments.
Are there some better solutions?
Yes; In c++17 you could use if constexpr with a trait to check the std::vector, like this.
#include <type_traits> // std::false_type, std::true_type
#include <vector>
// traits for checking wether T is a type of std::vector<>
template<typename T> struct is_std_vector final : std::false_type {};
template<typename... T> struct is_std_vector<std::vector<T...>> final : std::true_type {};
template<typename T>
class A /* final */
{
T mData;
public:
// ...constructor
void print() const /* noexcept */
{
if constexpr (is_std_vector<T>::value) // when T == `std::vector<>`
{
for (const auto element : mData)
std::cout << element << "\n";
}
else // for types other than `std::vector<>`
{
std::cout << mData << std::endl;
}
}
};
(See Live Online)
This way you keep only one template class and the print() will instantiate the appropriate part according to the template type T at compile time.
If you don not have access to C++17, other option is to SFINAE the members(Since c++11).
#include <type_traits> // std::false_type, std::true_type, std::enbale_if
#include <vector>
// traits for checking wether T is a type of std::vector<>
template<typename T> struct is_std_vector final : std::false_type {};
template<typename... T> struct is_std_vector<std::vector<T...>> final : std::true_type {};
template<typename T>
class A /* final */
{
T mData;
public:
// ...constructor
template<typename Type = T> // when T == `std::vector<>`
auto print() const -> typename std::enable_if<is_std_vector<Type>::value>::type
{
for (const auto element : mData)
std::cout << element << "\n";
}
template<typename Type = T> // for types other than `std::vector<>`
auto print() const -> typename std::enable_if<!is_std_vector<Type>::value>::type
{
std::cout << mData << std::endl;
}
};
(See Live Online)
What if I have more other data types like self-define vector classes
or matrices? Do I have to define many is_xx_vector?
You can check the type is a specialization of the provided one like as follows. This way you can avoid providing many traits for each type. The is_specialization is basically inspired from this post
#include <type_traits> // std::false_type, std::true_type
#include <vector>
// custom MyVector (An example)
template<typename T> struct MyVector {};
template<typename Test, template<typename...> class ClassType>
struct is_specialization final : std::false_type {};
template<template<typename...> class ClassType, typename... Args>
struct is_specialization<ClassType<Args...>, ClassType> final : std::true_type {};
And the print function could be in c++17:
void print() const /* noexcept */
{
if constexpr (is_specialization<T, std::vector>::value)// when T == `std::vector<>`
{
for (const auto element : mData)
std::cout << element << "\n";
}
else if constexpr (is_specialization<T, ::MyVector>::value) // custom `MyVector`
{
std::cout << "MyVector\n";
}
else // for types other than `std::vector<>` and custom `MyVector`
{
std::cout << mData << std::endl;
}
}
(See Live Online)
You need to implement a template class that uses a vector as template parameter. This worked for me.
template<typename T>
class A
{
public:
T data;
void print(void) {
std::cout << "Data output" << std::endl;
}
// other functions ...
};
template <typename T>
class A<std::vector<T>>
{
public:
std::vector<T> data;
void print() {
for (auto i : data) {
std::cout << "Vector output" << std::endl;
}
}
};
You could always use named tag dispatching to check if type provided by template user is vector.
A<std::vector<T>> notation won't work as you both try to take into account that T is type and vector of types which is contradicting with itself.
Below is code I used named tag dispatching as solution to your problem:
#include <iostream>
#include <vector>
#include <type_traits>
using namespace std;
template<typename T> struct is_vector : public std::false_type {};
template<typename T, typename A>
struct is_vector<std::vector<T, A>> : public std::true_type {};
template<typename T>
class A
{
public:
T data;
void print(std::true_type) {
for (auto& a : data) { std::cout << a << std::endl; }
}
void print(std::false_type) {
std::cout << data << std::endl;
}
void print() {
print(is_vector<T>{});
}
};
int main()
{
A<int> a;
a.data = 1;
a.print();
A<std::vector<int>> b;
b.data = { 1, 2 ,3 ,4 ,5 };
b.print();
return 0;
}
Succesfully compiled with https://www.onlinegdb.com/online_c++_compiler
Based on answer: Check at compile-time is a template type a vector
You can dispatch printing to another member function (static or not). For example:
template<typename T>
class A {
public:
T data;
void print() const {
print_impl(data);
}
private:
template<class S>
static void print_impl(const S& data) {
std::cout << data;
}
template<class S, class A>
static void print_impl(const std::vector<S, A>& data) {
for (const auto& d : data)
std::cout << d;
}
};

How to create a template class that can handle std::set with different type parameters

I need to write a template in C++ that implements an abstract version of a set. I can't find a solution (or worse, don't really understand what to do) about a compile error.
This is a simplified version of the main program I need to compile and run -- that is, I MUST NOT change anything in this:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <numeric>
#include <set>
#include <string>
#include "testset.h"
using namespace std;
struct string_size_less
{
bool operator()( const std::string& a,
const std::string& b )
{
return a.size() < b.size();
}
};
int main()
{
std::set<std::string> msgs;
msgs.insert("One");
msgs.insert("Two");
msgs.insert("Three");
set_ops<std::string> ops(msgs);
ops.list();
std::set<std::string, string_size_less> x;
x.insert("Hello");
x.insert("Ciao");
std::set<std::string, std::greater<std::string> > a;
a.insert(":-o");
set_ops<std::string> m(x);
m.list();
return 0;
}
I need to write the 'set_ops' class (in testset.h). I stripped all the non-relevant parts (that otherwise work):
#pragma once
#include <iostream>
#include <set>
using namespace std;
template <class T> class set_ops
{
private:
std::set<T> elements;
public:
set_ops(std::set<T> initialSet)
{
elements = initialSet;
}
void list() const;
};
template <class T> void set_ops<T>::list() const
{
for (typename set<T>::iterator i = elements.begin(); i != elements.end(); ++i) {
cout << "\t" << *i << endl;
}
}
When I try to compile this, I get the error:
In function 'int main()':
error: no matching function for call to 'set_ops<std::__cxx11::basic_string<char> >::set_ops(std::set<std::__cxx11::basic_string<char>, string_size_less>&)'
note: candidate: set_ops<T>::set_ops(std::set<T>) [with T = std::__cxx11::basic_string<char>]|
note: no known conversion for argument 1 from 'std::set<std::__cxx11::basic_string<char>, string_size_less>' to 'std::set<std::__cxx11::basic_string<char> >'
I have tried many things and tried to find a good example, etc., but so far found none. I know for example (and tried it) that if I add another template parameter like this:
template <class T, class U = std::less<T> > class set_ops
{
private:
std::set<T, U> elements;
public:
set_ops(std::set<T, U> initialSet)
{
elements = initialSet;
}
void list() const;
};
template <class T, class U> void set_ops<T, U>::list() const
{
for (typename set<T, U>::iterator i = elements.begin(); i != elements.end(); ++i) {
cout << "\t" << *i << endl;
}
}
then if I explicitly write:
set_ops<std::string, string_size_less> m(x);
it compiles and runs without error. But, again, I MUST NOT change anything in main(), so that's not an option.
If I keep the line from the original main(), I get the same compile error even with the changes in testset.h.
I'd really like to understand the problem (and hopefully the solution) here, if anyone could help. Thanks!
This can be achieved through polymorphism and a template constructor.
#include <utility>
#include <memory>
#include <iostream>
template <typename T>
class set_ops
{
private:
// Interface type.
class set_ops_iface
{
public:
virtual ~set_ops_iface();
virtual void list() const = 0;
};
// Concrete implementation for a U.
template <typename U>
class set_ops_impl : public set_ops_iface
{
private:
U value;
public:
explicit set_ops_impl(U);
virtual void list() const override;
};
private:
// Smart pointer to interface type.
std::unique_ptr<set_ops_iface> impl;
public:
// Template constructor that can take any kind of container (not just sets)
template <typename U>
set_ops(U);
void list() const;
};
// Template constructor creates a set_ops_impl<U> owned by the interface smart pointer.
template <typename T>
template <typename U>
set_ops<T>::set_ops(U initial) :
impl{std::make_unique<set_ops_impl<U>>(std::move(initial))} { }
template <typename T>
set_ops<T>::set_ops_iface::~set_ops_iface() { }
template <typename T>
template <typename U>
set_ops<T>::set_ops_impl<U>::set_ops_impl(U initial) :
value{std::move(initial)} { }
// real list() implementation is in set_ops_impl<U>
template <typename T>
template <typename U>
void set_ops<T>::set_ops_impl<U>::list() const {
for (auto const & i : value) {
std::cout << '\t' << i << '\n';
}
}
// set_ops::list proxies to the polymorphic implementation.
template <typename T>
void set_ops<T>::list() const {
impl->list();
}
(Demo)
Note that, curiously, we don't even use the T template argument. set_ops wouldn't even need to be a template type if main() didn't require that it is.
To add another member function, you have to:
Add the implementation to the set_ops::set_ops_impl template.
Add a proxy member to set_ops.
The other answer works because std::function uses a technique called "type erasure". If you don't want to keep multiple std::functions, you can instead implement type erasure yourself.
template<typename T>
struct set_ops_erased {
virtual ~set_ops_erased() = default;
virtual void list() = 0;
};
template<typename T, typename Comp>
struct set_ops_impl : set_ops_erased<T> {
std::set<T, Comp> s;
set_ops_impl(std::set<T, Comp> s) : s(std::move(s)) { }
void list() override {
for(auto &x : s) std::cout << "\t" << x << "\n"; // endl is normally not necessary
}
};
template<typename T>
class set_ops {
std::unique_ptr<set_ops_erased<T>> ops;
public:
template<typename Comp>
set_ops(std::set<T, Comp> s)
: ops(std::make_unique<set_ops_impl<T, Comp>>(std::move(s)))
{ }
void list() { ops->list(); }
};
In this case, there's no need to worry about writing all the copy/move constructors/assignments and destructors. They just do the right thing. Because there is just one allocation of set_ops_impl, there's no need to think about using a "guarding" std::unique_ptr to clean up the container while the set_ops is being constructed.
Without changing main file, but forgetting initial order of given set (as you don't specify expected output), you might do:
template <class T> class set_ops
{
private:
std::set<T> elements;
public:
template <typename Container>
set_ops(Container& c) : elements(c.begin(), c.end()) {}
void list() const {
for (const auto& e : elements) {
std::cout << "\t" << e << std::endl;
}
}
};

How to find all objects of class given in variadic template parameters

I want to find all objects of given types and add them to vector.
For now I have code:
template<class T>
void fill1(std::vector<Character*> &vec2)
{
for (int i = 0; i < GameObject::allObjects.size(); i++)
{
if (dynamic_cast<T>(GameObject::allObjects[i]))
{
vec2.push_back(dynamic_cast<Character*>(GameObject::allObjects[i]));
}
}
}
template<class First, class ...T>
void fill2(std::vector<Character*> &vec2)
{
fill1<First>(vec2);
fill2<T...>(vec2);
}
template<class ... T>
std::vector<Character*> SpecialList<T...>::get()
{
std::vector<Character*> vec2;
fill2<T...>(vec2);
return vec2;
}
The code doesn't compile at all.
The error we are getting is:
could not deduce template argument for 'First'
I know that all the given types are inherited from class Character and I have a vector of all my objects (GameObject::allObjects).
Instead of recursion use parameter pack expansion inside list initialization of a dummy array e.g.:
#include <vector>
#include <memory>
#include <tuple>
#include <iostream>
#include <algorithm>
template <class... Ts>
struct tag { };
template <class T>
struct Predicate {
template <class U>
bool operator()(std::shared_ptr<U> sp) const {
return std::dynamic_pointer_cast<T>(sp) != nullptr;
}
};
template <class... Ts, class T>
std::vector<std::shared_ptr<T>> all(std::vector<std::shared_ptr<T>> &v, tag<Ts...>) {
std::vector<std::shared_ptr<T>> result;
int dummy[] {(std::copy_if(v.begin(), v.end(), std::back_inserter(result), Predicate<Ts>{}),0)...};
static_cast<void>(dummy);
return result;
}
struct A {
virtual ~A() = default;
};
struct B: A { };
struct C: A { };
int main() {
std::vector<std::shared_ptr<A>> v { std::make_shared<A>(),
std::make_shared<A>(),
std::make_shared<B>(),
std::make_shared<B>(),
std::make_shared<C>(),
std::make_shared<C>() };
std::cout << all(v, tag<B, C>{}).size() << std::endl;
}
[live demo]

how to get outer class name from inner enum

basicly what i want to do is written in code. so , is there a way with templates or with something else get outer class name in global function ? is there a way to get this code work?
#include <iostream>
class A
{
public:
enum class B
{
val1,
val2
};
typedef B InnerEnum;
static void f(InnerEnum val)
{
std::cout << static_cast<int>(val);
}
};
template <typename T1>
void f(typename T1::InnerEnum val)
{
T1::f(val);
}
int main()
{
A::InnerEnum v = A::InnerEnum::val1;
f(v);
return 0;
}
You may create trait for that and manually feed it:
template <typename T>
struct outer_class;
template <>
struct outer_class<A::B> { using type = A;};
And then
template <typename E>
void f(E val)
{
using T = typename outer_class<E>::type;
T::f(val);
}

Specializing a method template for classes in a namespace

I'm using the following compile-time 'trick' (based on ADL) to create a function that is only valid/defined/callable by classes in the same namespace.
namespace Family1
{
struct ModelA{};
struct ModelB{};
template<typename T>
bool is_in_Family1(T const& t)
{
return true;
}
};
namespace Family2
{
struct ModelC{};
template<typename T>
bool is_in_Family2(T const& t)
{
return true;
}
};
Family1::ModelA mA;
Family2::ModelC mC;
is_in_Family1(mA); // VALID
is_in_Family1(mC); // ERROR
Now, I'd like to use this principle (or something similar) in order to produce a specialization of Foo::Bar (below) for classes belonging to each of the namespaces e.g. Family1.
// I would like to specialize the method template Bar for classes in Family1
// namespace; and another specialization for classes in Family2 namespace
struct Foo
{
template<typename T>
void Bar( T& _T ){}
};
For ease of maintenance and the large number of classes in each namespace, if possible, I'd like to perform this check without naming all the classes in a namespace.
Your "trick" has one big problem. Try calling is_in_Family1(make_pair(Family1::ModelA(), Family2::ModelC()) and you will see that return true, because ADL will look into both the namespaces of ModelA and ModelC (because of pair<ModelA, ModelC>).
Ignoring that problem, with using your functions it is straight forward.
template<typename T> struct int_ { typedef int type; };
struct Foo
{
template<typename T,
typename int_<decltype(is_in_Family1(*(T*)0))>::type = 0
>
void Bar( T& t ){}
template<typename T,
typename int_<decltype(is_in_Family2(*(T*)0))>::type = 0
>
void Bar( T& t ){}
};
That calls Bar depending on whether it is in family2 or family1.
struct Foo
{
template<typename T,
typename int_<decltype(is_in_Family1(*(T*)0))>::type = 0
>
void Bar( T& t, long){}
template<typename T,
typename int_<decltype(is_in_Family2(*(T*)0))>::type = 0
>
void Bar( T& t, long){}
template<typename T>
void Bar( T& t, int) {}
template<typename T>
void Bar( T& t ) { return Bar(t, 0); }
};
That one has also a generic fallback. And your code had undefined behavior because you used a reserved name. Don't use _T.
The quickest way I found to do this is using Boost Type Traits' is_base_of<>
I tried to use inheritence with template specialization but that didn't work because inheritance is ignored when template specialization is used so you'd have to specialize for each model. The answer to Partial specialization for a parent of multiple classes explains the problem.
Using type traits works provided you make Family1::ModelA and Family::ModelB subclasses of Family1:Family1Type and Family2::ModelC a subclass of Family2::Family2Type :
#include <iostream>
#include <boost/type_traits/is_base_of.hpp>
namespace Family1{
struct Family1Type{};
struct ModelA :public Family1Type{};
struct ModelB :public Family1Type{};
template<typename T>
bool is_in_Family1(const T& t){
return boost::is_base_of<Family1::Family1Type,T>::value;
}
};
namespace Family2{
struct Family2Type{};
struct ModelC :public Family2Type{};
template<typename T>
bool is_in_Family2(const T& t){
return boost::is_base_of<Family2::Family2Type,T>::value;
}
};
using namespace std;
int main(int argc, char *argv[]) {
Family1::ModelA mA;
Family2::ModelC mC;
std::cout << "mA is in Family1? " << is_in_Family1(mA) << std::endl;
std::cout << "mC is in Family2? " << is_in_Family2(mC) << std::endl;
//std::cout << "mC is in Family1? " << is_in_Family1(mC) << std::endl; //ERROR!
//std::cout << "mA is in Family2? " << is_in_Family2(mA) << std::endl; //ERROR!
return 0;
}
This results in the following output:
mA is in Family1? 1
mC is in Family2? 1
I don't think there is a way to declare Foo and specialize Foo::Bar<> in another namespace according to Specialization of 'template<class _Tp> struct std::less' in different namespace