Template Mutual Recursion - c++

I would like to have in my library a template function func such that the user can overload it with its own types. The problem is that my type system is of the form
T := A<T>, B<T>, C
As such, template<class T> void func(A<T>); needs template<class T> void func(B<T>); if it is specialised with T = B<C>. Reciprocally, if we instantiate func(B<T>) with T = A<C>, the B<T> specialisation needs the A<T> specialisation.
The problem until here could be solved declaring the template functions in some common header.
What I don't know how to approach is how to make this type system extensible. I would like that the user can define her own type template<class T> class D<T>; and implement her own template<class T> void func(D<T>);. In this case, I don't know how the user could forward declare her type so that in the specialisation A<D<C>> the function void func(A<T>); is able to find void func(D<T>);.
Is there any standard way of doing this?
Edit minimal working example of the problem:
// in A.hpp
namespace ns {
template<class T> struct A { T t; };
template<class T>
void fun (A<T> a) { fun(a.t); }
}
// B.hpp
namespace ns {
template<class T> struct B { T t; };
template<class T>
void fun (B<T> b) { fun(b.t); }
// C.hpp
#include <iostream>
namespace other {
template<class T>
struct C {};
}
namespace ns {
template<class T>
void fun(other::C<T> c) { std::cout << "C" << std::endl; }
}
// main.cpp
#include "A.hpp"
#include "B.hpp"
#include "C.hpp"
namespace ns {
void f () {
fun(A<B<other::C<int>>>());
}
}
int main () {
ns::f();
}
This example doesn't compile. It just compiles if we reorder the includes in main.cpp as
#include "C.hpp"
#include "B.hpp"
#include "A.hpp"
Now, this is clearly a hack. With this design the user will not be able to instantiate both A<B<C<int>>> and B<A<C<int>>>. A solution to this would be to forward declare A and B in some other template and include it in both A.hpp and B.hpp. The problem now comes when you try to let the user of the library define her own types. If the user of the library defines her own type template<class T> class D;, she cannot forward declare, and then, if she tries to instantiate A<D<C<int>>>, the compilation will fail.
In this example the namespace other represents a namespace over which I don't have control, and C represents a preexisting class in some other library. This can be thought as some boost class or similar. The ns namespace is the one that my library defines.

What about if fun() is a static method in a template class?
So you can partial specialize the class?
I mean something like
// 000.h
#ifndef h_000__h
#define h_000__h
namespace ns
{
template <typename T>
struct foo;
}
#endif
// 001.h
#ifndef h_001__h
#define h_001__h
#include <iostream>
#include "000.h"
namespace ns
{
template<class T>
struct A
{ T t; };
template <typename T>
struct foo<A<T>>
{
static void fun (A<T> a)
{ std::cout << "A<T> fun" << std::endl; foo<T>::fun(a.t); }
};
}
#endif
// 002.h
#ifndef h_002__h
#define h_002__h
#include <iostream>
#include "000.h"
namespace ns
{
template <typename T>
struct B
{ T t; };
template <typename T>
struct foo<B<T>>
{
static void fun (B<T> a)
{ std::cout << "B<T> fun" << std::endl; foo<T>::fun(a.t); }
};
}
#endif
// 003.h
#ifndef h_003__h
#define h_003__h
#include <iostream>
#include "000.h"
namespace other
{
template <typename T>
struct C
{ };
}
namespace ns
{
template <typename T>
struct foo<other::C<T>>
{
static void fun (other::C<T> a)
{ std::cout << "C<T> fun" << std::endl; }
};
}
#endif
// main.cpp
#include "001.h"
#include "002.h"
#include "003.h"
namespace ns
{
void f ()
{
using type = A<B<other::C<int>>>;
foo<type>::fun(type{});
}
}
int main ()
{
ns::f(); // print A<T> fun \n B<T> fun \n C<T> fun \n
}

Related

add function member to a template class conditionally [duplicate]

This question already has answers here:
How to conditionally add a function to a class template?
(5 answers)
Closed 2 years ago.
I have a class template defined as follow
template<typename T>
class A
{
T t_;
// void f();
};
My question is how to add the f() method only if the type T is integer without compilation error.
int main()
{
A<int> a; // OK
A<string> b; // OK
}
Example :
#include <type_traits>
#include <new>
#include <iostream>
#include <string>
template <typename T>
struct Foo
{
T t;
template <typename..., typename U = T>
std::enable_if_t<std::is_same_v<T, int>> say_hello() { std::cout << "Hello"; }
};
int main()
{
Foo<int>();
Foo<double>();
}
Error C2938 'std::enable_if_t<false,void>' : Failed to specialize alias template
Thank you.
You can enable specific functions using type_traits and SFINAE:
#include <iostream>
#include <string>
#include <type_traits>
template<typename T>
class A
{
public:
template<typename U = T, std::enable_if_t<std::is_integral_v<U>, int> = 0>
void f() {
std::cout << "int " << t_ << '\n';
}
private:
T t_;
};
int main() {
A<int> a;
a.f();
A<std::string> s;
// s.f(); // error: no member named 'f' in 'A<std::__cxx11::basic_string<char> >'
}
If you have many integer specific functions you can put them in a class of its own and inherit that class only if T is integral.
#include <iostream>
#include <string>
#include <type_traits>
template<typename Atype>
class int_functions {
public:
Atype* This() { return static_cast<Atype*>(this); }
void f() {
std::cout << "int " << This()->t_ << '\n';
}
};
template<typename Atype>
class non_int_functions {
};
template<typename T>
class A : public std::conditional_t<std::is_integral_v<T>, int_functions<A<T>>,
non_int_functions<A<T>>>
{
friend std::conditional_t<std::is_integral_v<T>, int_functions<A<T>>,
non_int_functions<A<T>>>;
public:
private:
T t_;
};

Nested template 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);
}

Constraint API template types neatly

I have a template API function in my class called template<typename T> T Get(/*stuff*/);. My source file implements this function for a certain list of T types. If the user wants to use a type that I have not implemented, then I want the result to be a compile error, and not a linker error. I don't care much about the compile message yet. Here's what I've got so far:
MyClass.h
#pragma once
#define API_TYPE(X) \
template<> struct Implemented<X> : public API<X> {}
namespace MyClassAPI
{
template<typename T> struct API
{
static T Get(const T&);
};
template<typename T> struct Implemented {};
API_TYPE(bool);
}
class MyClass
{
template<typename T> friend struct MyClassAPI::API;
public:
template<typename T> T Get(const T& t) const
{
return MyClassAPI::Implemented<T>::Get(t);
}
};
MyClass.cpp
#include "MyClass.h"
namespace MyClassAPI
{
template<typename T> T API<T>::Get(const T& t) { return t; }
//template struct API<bool> //Why do I need this?
}
main.cpp
#include "MyClass.h"
#include <iostream>
#include <cassert>
using namespace std;
// Main File
int main() {
MyClass c;
cout << "Getting true: " << c.Get(true) << endl;
return 0;
}
So my question is about a line in MyClass.cpp. Why do I need to replicate the API<bool> explicit declaration in the source file with template struct API<bool>;? Shouldn't it know to expand the template function definition from the header file's declaration when Implemented<bool> : public API<bool> inherits from it?
Also, is there a way to do this without declaring my accepted type list twice?
Error without the line:
g++ -Wfatal-errors -Werror -std=c++11 -g -O0 -Wall -c MyClass.cpp -o MyClass.o
g++ -Wfatal-errors -Werror -std=c++11 -g -O0 -Wall test.cpp MyClass.o -o test
/tmp/ccVxp4F3.o: In function `bool MyClass::Get<bool>(bool const&) const':
MyClass.h:25: undefined reference to `MyClassAPI::API<bool>::Get(bool const&)'
collect2: error: ld returned 1 exit status
make: *** [test] Error 1
The problem with your template is you're defining it's members in a separate translation unit, hence they are not visible to main.cpp, and C++ does not support separate translation of templates.
When you use template struct API<bool>; you ask the compiler to explicitly instantiate API<T> for T = bool. However, when doing so, you should also let the other translations units know that the instantiation takes place elsewhere by having a similar directive in the header file with template declaration:
extern template struct API<bool>;
Otherwise, move the definition of Get to the header file or include .cpp file in the header file (not recommended) and rely on the compiler to instantiate template members for you.
As about limiting the list of viable template parameters, I suggest an approach based on template metaprogramming.
First we'll define some facility for checking whether a type belongs to a list of types, let's call it is_in<DesiredType, ViableTypes...>. It will accept as template parameters a type T to look for and a list of types InTypes... for search, and provide result by a static boolean member available at compile-time.
It is implemented as a simple recursive algorithm on a list, checking each element of the list against DesiredType until DesiredType is found or the end of list is met:
#include <type_traits>
template<typename...> struct is_in;
template<typename T, typename InType, typename... InTypes> struct is_in<T, InType, InTypes...> {
static constexpr bool value = std::is_same_t<T, InType> ||
is_in<T, InTypes...>::value;
}
template<typename T> struct is_in<T> {
static constexpr bool value = false;
}
Now, having is_in, we can just use static_assert and explicitly specify viable types for a template:
template<typename T> struct API
{
// Only allow API<bool> and API<int>
static_assert(is_in<T, bool, int>::value, "invalid template type for API<T>");
static T Get(const T&);
};
You almost have it there.
You need update MyClass.h to provide explicit instantiations of couple of functions and implement them in MyClass.cpp.
In the .h file, add:
// Explicit instantiations
namespace MyClassAPI
{
template<> int API<int>::Get(const int&);
template<> double API<double>::Get(const double&);
}
In the .cpp file, add:
// Implement the explicit instantiations
namespace MyClassAPI
{
template<> int API<int>::Get(const int& in)
{
// Add whatever logic that makes sense for this type.
return 2*in;
}
template<> double API<double>::Get(const double& in)
{
// Add whatever logic that makes sense for this type.
return 10*in;
}
}
Here's a single file version of working code:
#define API_TYPE(X) \
template<> struct Implemented<X> : public API<X> {}
namespace MyClassAPI
{
template<typename T> struct Implemented;
template<typename T> struct API
{
static T Get(T const&);
};
API_TYPE(int);
API_TYPE(double);
}
class MyClass
{
template<typename T> friend struct MyClassAPI::API;
public:
template<typename T> T Get(const T& t) const
{
return MyClassAPI::Implemented<T>::Get(t);
}
};
// Explicit instantiations
namespace MyClassAPI
{
template<> int API<int>::Get(const int&);
template<> double API<double>::Get(const double&);
}
#include <iostream>
int main()
{
MyClass a;
std::cout << a.Get<int>(10) << std::endl;
std::cout << a.Get<double>(10) << std::endl;
// Does not work. Produces compiler error.
// std::cout << a.Get<float>(10) << std::endl;
}
// Implement the explicit instantiations
namespace MyClassAPI
{
template<> int API<int>::Get(const int& in)
{
return 2*in;
}
template<> double API<double>::Get(const double& in)
{
return 10*in;
}
}
Output:
20
100
Update
Here'a multiple file version:
MyClass.h:
#pragma once
#define API_TYPE(X) \
template<> struct Implemented<X> : public API<X> {}
namespace MyClassAPI
{
template<typename T> struct Implemented;
template<typename T> struct API
{
static T Get(T const&);
};
API_TYPE(int);
API_TYPE(double);
}
class MyClass
{
template<typename T> friend struct MyClassAPI::API;
public:
template<typename T> T Get(const T& t) const
{
return MyClassAPI::Implemented<T>::Get(t);
}
};
// Explicit instantiations
namespace MyClassAPI
{
template<> int API<int>::Get(const int&);
template<> double API<double>::Get(const double&);
}
MyClass.cc:
#include "MyClass.h"
// Implement the explicit instantiations
namespace MyClassAPI
{
template<> int API<int>::Get(const int& in)
{
return 2*in;
}
template<> double API<double>::Get(const double& in)
{
return 10*in;
}
}
main.cc:
#include <iostream>
#include "MyClass.h"
int main()
{
MyClass a;
std::cout << a.Get<int>(10) << std::endl;
std::cout << a.Get<double>(10) << std::endl;
// Does not work.
// std::cout << a.Get<float>(10) << std::endl;
}
It also builds successfully and produces the same result.

undefined reference on Friend template function

I am trying to implement a friend template function over a normal class.
fren.h
#include <iostream>
namespace sn{
class Fren{
private:
int x;
public:
Fren(int y):x(y){
}
template<typename B>
friend void getValue(B& asd);
};
template<typename B>
void getValue(B& asd);
}
fren.cpp
#include "fren.h"
namespace sn{
template<typename B>
void getValue(B& asd){
std::cout<<asd.x<<std::endl;
}
}
main.cpp
#include "fren.h"
int main() {
sn::Fren f(10);
sn::getValue(f);
return 0;
}
I am trying to get the private value x of Fren.
But i get the "undefined reference to" error.
First off, unless there is a solid reason for otherwise, most of this belongs in a single header file. See "Why can templates only be implemented in the header file?" for why.
That said, if you want to use explicit instantiation for your function template, you can. Note the following, which is also more restrictive than your friending. This code only friends the function templates with matching template arguments to Fren:
func.h
#ifndef SAMPLE_FUNC_H
#define SAMPLE_FUNC_H
namespace sn
{
template<class T>
struct Fren;
template<class T>
void getValue(const Fren<T>& s);
template<class T>
struct Fren
{
friend void getValue <>(const Fren<T>&);
Fren() : x(42) {}
private:
int x;
};
} // namespace
#endif
func.cpp
#include "func.h"
#include <iostream>
namespace sn
{
template<class T>
void getValue(const Fren<T>& s)
{
std::cout << s.x << ':' << __PRETTY_FUNCTION__ << '\n';
}
// explicit instantiation here
template void getValue <int> (const Fren<int>&);
}
main.cpp
#include <iostream>
#include <string>
#include "func.h"
int main()
{
sn::Fren<int> s;
sn::getValue(s);
}
Output
42:void sn::func(const S<T> &) [T = int]
Compiled with Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
In short, your code appears to be missing the actual explicit instantiation.

Creating concept for member template function for use with boost::any in c++

I am trying to create a concept for use with boost::any. This concept should say that
a class has ha member function with signatur void templateFunction(T t). I have gotten this to compile and working fine, but only for one type at a time. Is what I am trying to do impossible?
#include <iostream>
#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/any_cast.hpp>
#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/operators.hpp>
#include <boost/type_erasure/member.hpp>
#include <boost/type_erasure/free.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/any.hpp>
using namespace std;
namespace mpl = boost::mpl;
using namespace boost::type_erasure;
class Foo
{
public:
template <class T>
void templateFunction(T t)
{
cout << t << endl;
}
};
template<class C, class T>
struct has_template_function
{
static void apply(C& cont, const T& arg) { cont.templateFunction(arg); }
};
namespace boost
{
namespace type_erasure
{
template<class C, class T, class Base>
struct concept_interface<has_template_function<C, T>, Base, C> : Base
{
void templateFunction(typename as_param<Base, const T&>::type arg)
{ call(has_template_function<C, T>(), *this, arg); }
};
}
}
int main()
{
any<has_template_function<_self, int>, _self&> c = Foo();
c.templateFunction(5);
//Compile error: cannot convert parameter 1 from 'const char [6]' to 'const int &'
//c.templateFunction("Hello");
return 0;
}
This is kind of possible by overloading, and documented in the official Boost.TypeErasure documentation.
The caveat is, as said in the comments:
You can't type-erase templates and keep their polymorphic nature
Therefore, you will have to specify the overloads explicitly in the requirements for your boost::typeerasure::any type.
You need to modify your concept interface as described in the docs, and add a string overload to the requirements section.
Your example, modified to handle overloads:
#include <iostream>
#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/any_cast.hpp>
#include <boost/type_erasure/builtin.hpp>
#include <boost/type_erasure/operators.hpp>
#include <boost/type_erasure/member.hpp>
#include <boost/type_erasure/free.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/any.hpp>
#include <string>
#include <utility>
using namespace std;
namespace mpl = boost::mpl;
using namespace boost::type_erasure;
struct FooStruct
{
template <class T>
void templateFunction(T t)
{
cout << t << endl;
}
};
template<class T, class U>
struct has_template_function
{
static void apply(T& t, const U& u) { t.templateFunction(u); }
};
namespace boost {
namespace type_erasure {
template<class T, class U, class Base, class Enable>
struct concept_interface< ::has_template_function<T, U>, Base, T, Enable> : Base
{
typedef void _fun_defined;
void templateFunction(typename as_param<Base, const U&>::type arg)
{
call(::has_template_function<T, U>(), *this, arg);
}
};
template<class T, class U, class Base>
struct concept_interface< ::has_template_function<T, U>, Base, T, typename Base::_fun_defined> : Base
{
using Base::templateFunction;
void templateFunction(typename as_param<Base, const U&>::type arg)
{
call(::has_template_function<T, U>(), *this, arg);
}
};
}
}
ostream& operator<<(ostream& os, const std::pair<int, string>& pair) {
os << "(" << pair.first << ", " << pair.second << ")";
return os;
}
int main()
{
any<
mpl::vector
<
has_template_function<_self, int>,
has_template_function<_self, std::string>,
has_template_function<_self, std::pair<int,std::string>>
>
, _self&> c = FooStruct();
c.templateFunction(5);
c.templateFunction("Hello");
c.templateFunction(std::make_pair(5, "Hello"));
return 0;
}