I have a template class as below:
template<typename A> struct TaskInfo{
typedef A _A;
static void bar(A a){blah blah...} };
template <typename TaskInfo> class Task {
typedef typename TaskInfo::_A A;
bar(A a){
blah blah...
TaskInfo::bar(a);
}
}
and I have an object that has a collection of these classes:
using TaskInfoX= TaskInfo<int>; //ignore the bar implementation for the time being.
using TaskInfoY= TaskInfo<double>;
class TaskCollection(){
TaskCollection(){
auto Task1=new Task<TaskInfoX>;
auto Task2=new Task<TaskInfoY>;
Register(Task1);
Register(Task2);
}
Register(...);
}
I want to know if it is possible to define an enum list:
enum TaskEnum
{
Etask1,
Etask2
};
and a function getTask such that in my app I can have:
int main {
TaskCollection collection;
int testInt;
double testDouble;
collection.getTask(Etask1)->bar(testInt);
//collection.getTask(Etask1)->bar(testDouble); //want compile error.
collection.getTask(Etask2)->bar(testDouble);
}
I know that I can have CRTP or the virtual inheritance equivalent that allows me to pass variadic arguments for bar() but I want to have type checking on the parameters of the bar function at compile time. Is this impossible in C++?
Update: Apologise for the typo. That was meant to be: getTask(task1). basically the outside world doesn't know about the underlying structure of the tasks and only knows them based on their public enum keys. Also note that in general there would be additional tasks potentially reusing the typeInfoX parameter.
First, to have error if type is not an exact match, you may use the following:
template <typename T>
class Task
{
public:
using type = typename T::type;
void bar(type a) { T::bar(a); }
template <typename U>
std::enable_if_t<!std::is_same<std::decay_t<U>, type>::value>
bar(U&&) = delete;
};
Then, with some helpers:
template <TaskEnum> struct TaskMap;
template <> struct TaskMap<Etask1> { using type = Task<TaskInfoX>; };
template <> struct TaskMap<Etask2> { using type = Task<TaskInfoY>; };
Your collection could be something like:
class TaskCollection
{
public:
Task<TaskInfoX> taskX;
Task<TaskInfoY> taskY;
template <TaskEnum E>
typename TaskMap<E>::type&
getTask();
};
template <>
Task<TaskInfoX>& TaskCollection::getTask<Etask1>() { return taskX; }
template <>
Task<TaskInfoY>& TaskCollection::getTask<Etask2>() { return taskY; }
With final usage:
collection.getTask<Etask1>().bar(testInt);
collection.getTask<Etask1>().bar(testDouble);//error:call to deleted member function 'bar'
collection.getTask<Etask2>().bar(testDouble);
Demo
You can always template a concrete class with primitives. So instead of:
using TaskInfoX= TaskInfo<int>;
using TaskInfoY= TaskInfo<double>;
you can just have
template<> class Task<TaskEnum::Task1> : public TaskInfo<int>{}
template<> class Task<TaskEnum::Task2> : public TaskInfo<double>{}
and then define a template function:
template<TaskEnum taskE>
Task<taskE>* getTask() {}
You will need to derive template class Task from a base class so you can put it in a map, and you should define a map
std::map<TaskEnum,TaskBase*> taskMap;
and in getTask you can just do a static cast:
static_cast<Task<taskE>* >(taskBasePtr);
I think std::tuple is what you need:
auto my_tuple = std::make_tuple(Task<TaskInfoX>(), Task<TaskInfoY>());
std::get<Task<TaskInfoX>>(my_tuple).bar(12);
// actually, this is not an error because double can be convert to int
std::get<Task<TaskInfoX>>(my_tuple).bar(12.323);
Given the way Task1 and Task2 are stored in your TaskCollection class, I cant see an obvious way to implement getTask as a template, but you can overload it.
class TaskCollection
{
//...
Task<TaskInfoX> GetTask(Task<TaskInfoX> task)
{
return Task1;
}
Task<TaskInfoY> GetTask(Task<TaskInfoY> task)
{
return Task2;
}
};
If your real case works in with double and int then you need to supress the conversion from double to int in order to achieve this compile-time error...
//collection.getTask(Task1)->bar(testDouble); //want compile error.
one way to do this is to declare but not define a template version of bar in your TaskInfo
template<typename A> struct TaskInfo
{
static void bar(A a){blah blah...}
template<typename T> static void bar(T a); // deliberately not defined
//...
};
you still define your existing bar function for the type you do want to handle, but now, in the case that you want to fail, the compiler will try to call the template version of bar (with T as a double) in preference to calling the int version with a conversion from double to int. The resulting error in VS2015 is
error LNK2019: unresolved external symbol "public: static void __thiscall C::bar(double)
but if no code tries to call it then it doesn't matter that it is not defined an there is no error.
(It wasn't clear to me what the question was regarding the enum)
Related
I was wondering how we can declare an interface in C++ without using virtual functions. After some internet searching I put together this solution:
#include <type_traits>
using namespace std;
// Definition of a type trait to check if a class defines a member function "bool foo(bool)"
template<typename T, typename = void>
struct has_foo : false_type { };
template<typename T>
struct has_foo<T, typename enable_if<is_same<bool, decltype(std::declval<T>().foo(bool()))>::value, void>::type> : true_type { };
// Definition of a type trait to check if a class defines a member function "void bar()"
template<typename T, typename = void>
struct has_bar : false_type { };
template<typename T>
struct has_bar<T, typename enable_if<is_same<void, decltype(std::declval<T>().bar())>::value, void>::type> : true_type { };
// Class defining the interface
template <typename T>
class Interface{
public:
Interface(){
static_assert(has_foo<T>::value == true, "member function foo not implemented");
static_assert(has_bar<T>::value == true, "member function bar not implemented");
}
};
// Interface implementation
class Implementation:Interface<Implementation>{
public:
// If the following member functions are not declared a compilation error is returned by the compiler
bool foo(bool in){return !in;}
void bar(){}
};
int main(){}
I'm planning to use this design strategy in a project where I will use static polymorphism only.
The C++ standard I will use in the project is C++11.
What do you think are the pros and cons of this approach?
What improvements can be made on the code I proposed?
EDIT 1:
I just realised that inheriting from Interface is not needed. This code could also be used:
class Implementation{
Interface<Implementation> unused;
public:
bool foo(bool in){return !in;}
void bar(){}
};
EDIT 2-3:
One major difference between the static_assert solution (with or without CRTP) and the standard CRTP is that the CRTP does not guarantee that the derived class implements all the interface members. E.g., the following code compiles correctly:
#include <type_traits>
using namespace std;
template< typename T>
class Interface{
public:
bool foo(bool in){
return static_cast<T*>(this)->foo(in);
}
void bar(){
static_cast<T*>(this)->bar();
}
};
class Implementation: public Interface<Implementation>{
public:
// bool foo(bool in){return !in;}
// void bar(){}
};
int main(){}
An error about a missing member function will be returned by the compiler only when the functions foo or bar will be required.
The way I see it, the static_assert solution feels more like an interface declaration than CRTP alone.
An common way to implement static polymorphism is to use CRTP.
With this pattern, you define an templated interface class, whose methods forward to the template:
// Interface
template <typename T>
struct base {
void foo(int arg) {
static_cast<T*>(this)->do_foo(arg);
}
};
You implementation the inherits from the base class and implements the methods:
// Implementation
struct derived : base<derived> {
void do_foo(int arg) {
std::cout << arg << '\n'
}
};
This pattern has the advantage that it looks "feels" a lot like regular runtime polymorphism, and the error messages are generally quite sane. Because all the code is visible to the compiler, everything can be inlined so there's no overhead.
It appears that you want to implement concepts (lite). You may want to read the article before attempting an implementation.
Absent compiler support, you can partially implement this idea. Your static_assert idea is a known way to express interface requirements.
Consider the Sortable example from the link. You can create a class template Sortable, use static_assert to assert all kind of thinks about the template parameter. You explain to your users that they need to implement a certain cet of methods, and to enforce that set is implemented, they need to make use of Sortable<TheirClass> one way or another.
In order to express, right in a function declaration. the idea that your function requires a Sortable, you will have to resort to something like this:
template <typename Container>
auto doSomethingWithSortable (Container&) -> std::enable_if<Implements<Container, Sortable>>::type;
I don't have a lot of experience with templates but I am wondering if the following scenario is possible. Assume we have a class S with static member stat. I can get it to dynamically generate different code using typeid as:
template <class S>
void foo()
{
if (typeid(S::stat) == typeid(AType))
implementation 1;
else
implementation 2;
}
But since all information is known at compile time is it possible to create a specialization of foo for S::stat being of type Atype?
You're probably looking to do something like this:
template<typename T> class foo_impl {
public:
static void foo()
{
// This is your implementation 2
}
};
template<> class foo_impl<AType> {
public:
static void foo()
{
// This is your implementation 1
}
};
template <class S>
void foo()
{
foo_impl<typename S::Stat>::foo();
}
One common way of solving this problem is through tag dispatching. We can, at compile time, produce different types for whether or not S::stat matches AType - and use those types to call different overloads:
template <class S>
void foo() {
foo_impl(std::is_same<decltype(S::stat), AType>{});
}
void foo_impl(std::true_type /* S::stat matches AType */) {
// implementation 1
}
void foo_impl(std::false_type /* S::stat doesn't match AType */) {
// implementation 2
}
I was not able to utilize the decltype solution because my compiler does not support it.
I was able to utilize the foo_impl class solution but only when I declare MyClass as:
class MyClass {
public:
typedef AType Stat;
static const Stat stat = VAL;
...
}
It appears a forward declaration is causing an issue when specializing some template functions within a template class. I am specializing the class also as it's necessary in order to specialize the function, and this seems to be causing the issue.
Edit: Second question about pre-creating functions for process function:
processor.H
namespace OM{
template<typename MatchT> //fwd decl. ERROR 2. see below.
class Manager;
template<typename MatchT>
class Processor
{
public:
Processor(Manager<MatchT>& mgr_):_manager(mgr_) {}
template<int P>
void process();
void doProcess();
private:
Manager<MatchT>& _manager;
template<int P, int... Ps>
struct table : table<P-1,P-1, Ps... > {};
template<int... Ps>
struct table<0, Ps...>
{
static constexpr void(*tns[])() = {process<Ps>...};
};
static table<5> _table;
};
}
#include "processor.C"
processor.C
namespace OM{
#include "MyManager.H" (includes MyManager/MyConfig)
template<typename MatchT>
template<int P>
inline void Processor<MatchT>::process()
{
...
_manager.send(); //this works..
}
template <> template <>
inline void Processor<MyManager<MyConfig> >::process<1>()
{
_manager.send(); //ERROR 1 - see below.
}
//ERROR here:
template<typename MatchT>
void doProcess()
{
Processor<MatchT>::_table::tns[2](); ERROR 3 below.
}
}
compile errors:
1. error: invalid use of incomplete type 'class Manager <MyManager<MyConfig> >'
2. error: declaration of 'class Manager<MyManager<MyConfig> >'
class Manager;
3. error: no type name '_table' in "class Processor<MyManager<MyConfig> >'
I'm not calling this from a specialized function, so I'm not sure
why I'm getting this.
I can move things around a bit to ensure the _manager calls are not within the specialized functions, but I'd rather not if I don't have to.
I played around with this, I think now I get a similar result.
The problem is the template specialisation and forward declaration together. This should be eqvivalent:
template<typename T> struct A;
template<typename T> class B
{
template<int N>
T f();
};
template<typename T> class B<A<T>>
{
A<T> *a;
template<int N>
T f();
};
template<typename T> struct A{ T i=1; };//works
template<>
template<>
int B<A<int>>::f<1>()
{
return a->i + 1;
}
//template<typename T> struct A { T i = 1; };//error
int main()
{
B<A<int>> b;
}
The compilation for templates comes in two stages:
First, it checks syntax and (some) dependence. So, for example if a in B<A<T>> was not a pointer/reference, but the object itself, it could compile, if that B<A<T>> is constructed after A is defined. (worked for me)
So the second is when the compiler inserts the arguments, here, the compiler must know all objects to generate code.
When fully specialising, as above, the compiler is forced to know all types. It already knows, that f function depends on the implementation of A, so it cannot generate the code.
Therefore you have to define A or Manager before the function specialisation.
I'm using my class as a template parameter of one of its parent class, and that parent class uses it in a template argument (though sizeof()).
And the compiler gives me:
error : incomplete type 'Invoker::workerClass {aka MyClass}' used in nested name specifier
Yet the class is well defined in the file. I guess this is because the child class isn't instantiated at the moment of the base class' instantiation, yet that kind of thing happens with CRTP and there's no problems.
The reason I use the child class in the template argument is to do a different function call if the child class has, or doesn't have, a specific function.
Here's a minimal code for testing
/* Structure similar to boost's enable if, to use
SFINAE */
template <int X=0, class U = void>
struct test {
typedef U type;
};
enum Commands {
Swim,
Fly
};
/* Structure used for template overloading,
as no partial function template specialization available */
template<Commands T>
struct Param {
};
template <class T>
class Invoker
{
public:
typedef T workerClass;
workerClass *wc() {
return static_cast<workerClass*>(this);
}
template <Commands command>
void invoke() {
invoke2(Param<command>());
}
/* If the child class has those functions, call them */
/* Needs template paramter Y to apply SFINAE */
template<class Y=int>
typename test<sizeof(Y)+sizeof(decltype(&workerClass::fly))>::type
invoke2(Param<Fly>) {
wc()->fly();
}
template<class Y=int>
typename test<sizeof(Y)+sizeof(decltype(&workerClass::swim))>::type
invoke2(Param<Swim>) {
wc()->shoot();
}
template<Commands command>
void invoke2(Param<command>) {
/* Default action */
printf("Default handler for command %d\n", command);
}
};
template <class T, class Inv = Invoker<T> >
class BaseClass : public Inv
{
public:
template<Commands command>
void invoke() {
Inv::template invoke<command>();
}
};
class MyClass : public BaseClass<MyClass>
{
public:
void swim() {
printf("Swimming like a fish!\n");
}
/* void fly(); */
};
void testing() {
MyClass foo;
foo.invoke<Fly>(); /* No 'void fly()' in MyClass, calls the default handler */
foo.invoke<Swim>(); /* Should print the swimming message */
}
The error happens at the line:
typename test<sizeof(Y)+sizeof(decltype(&workerClass::fly))>::type
So, is there any compiler that supports this, or is this explicitely specified by the standard as an invalid use of templates? Do I have to change the way I'm doing this and find a way around? CRTP is giving me hope the code might be valid, but I'm not sure.
If this really isn't possible, then why exactly, and why does CRTP work?
The solution was, as ildjarn pointed out, to add another level of indirection.
That is done by changing the test function to accept types:
template <typename X, class U = void>
struct test {
typedef U type;
};
And then pass the child class as a template parameter, instead of specifying it from the get go:
template<class Y=workerClass>
typename test<decltype(&Y::fly)>::type
invoke2(Param<Fly>) {
wc()->fly();
}
template<class Y=workerClass>
typename test<decltype(&Y::swim)>::type
invoke2(Param<Swim>) {
wc()->swim();
}
That way the nested specifier is evaluated only when the function is called and not at the class evaluation, and by that time the child class is already evaluated. Plus with the possibility to pass default template argument, we can call the function without any template parameters.
The template is also much more readable now. And the sample code works just fine now:
class MyClass : public BaseClass<MyClass>
{
public:
void swim() {
printf("Swimming like a fish!\n");
}
/* void fly(); */
};
void testing() {
MyClass foo;
foo.invoke<Fly>(); /* No 'void fly()' in MyClass, calls the default handler */
foo.invoke<Swim>(); /* Should print the swimming message */
}
One of my classes declares a templated function:
template<class A, class B>
A do_something(const std::vector<B> &data)
which I'd like to partially specialize on typename A. B is a family of types that implement a pretty minimal interface, and we use a lot of them, so I'd like my specialization to be generic on B. I suspect this is doubly vexing as typename A is used only as the return type.
From the internet, I've gleaned that I can't partially specialize a function, so I've created a class as follows:
template<class A, class B>
class do_something_implementation {
public:
do_something_implementation(const std::vector<B> &data_) {
data = data_;
}
int do_something_implementation<int, B>::operator()() {
/* Complicated algorithm goes here... */
}
double do_something_implementation<double, B>::operator()() {
/* Different complicated algorithm goes here... */
}
private:
std::vector<B> data;
}
When I try to compile that (using Visual Studio 2008), the compiler crashes (!) and I get the following error:
fatal error C1001: An internal error has occurred in the compiler.
I assume this is my problem and not the compiler's. Is there a better way to express the partial specialization I'm aiming for?
Usually, it goes like this:
template <typename A, typename B>
struct DoSomethingHelper
{
static A doIt(const std::vector<B> &data);
};
template <typename B>
struct DoSomethingHelper<double, B>
{
static double doIt(const std::vector<B> &data) { ... }
};
template <typename B>
struct DoSomethingHelper<int, B>
{
static int doIt(const std::vector<B> &data) { ... }
};
template<class A, class B>
A do_something(const std::vector<B> &data)
{ return DoSomethingHelper<A, B>::doIt(data); }
Now that you've seen the classic forward to static method, there is actually another way when the type for which to specialize is "complete".
You may not be able to partially specialize a function, but you can perfectly overload it.
template <typename A, typename B>
A do(std::vector<B> const& data) { return this->doImpl(data, (A*)0); }
template <typename A, typename B>
A doImpl(std::vector<B> const& B, A*) { // generic implementation }
template <typename B>
int doImpl(std::vector<B> const& B, int*) { // int implementation }
template <typename B>
double doImpl(std::vector<B> const& B, double*) { // double implementation }
The trick is to pass an "unused" argument to doImpl for the sole purpose of actually selecting the right implementation (thanks to overload resolution).
Here I simply chose to pass (A*)0, because this does not involve A's constructor (in case it's non trivial).
This dispatch idiom is what is used in the STL to implement some algorithm with better efficiency for some iterator categories (for example, std::distance is O(1) for random iterators).
I find it much more lightweight that using a helper class with static methods and partial specializations... but maybe that's just me :)
People typically just forward to a static implementation.
template<class A, class B> class X;
template<class A, class B> friend class X;
template<class A, class B> class X {
public:
static A do_something(class_type* not_this, const std::vector<B>& data) {
//...
}
};
// partially specialize
template<class A, class B>
A do_something(const std::vector<B> &data) {
return X<A, B>::do_something(this, data);
};
Not a solution to your problem (there are a couple already there), but some of the things that are wrong in your code:
You are missing a struct or class keyword in the template class declaration:
template <typename A, typename B> struct do_something_implementation {
// ^^^^^^
Inside the class definition, member functions must not use a qualified name, regardless of whether the class is a template or not:
class A {
void A::foo() {} // Error, should be: void foo() {}
};
Member template specializations cannot appear inside the class definition, but at the namespace level:
class B {
template <typename T> void foo( T );
};
template <> void B::foo<int>( int ) {}
template <> void B::foo<double>( double ) {}
Plus on your case, the member function is not a template, but rather a non-templated member function (the template is the containing class, not the function itself). What your code is effectively trying to do is defining other class' member functions inside the general template, kind of trying to do.
Overall there was enough errors to make parsing the code almost impossible for the compiler to identify what you were trying to do and provide a good error message, but still, it should have provided any error message pointing to the first line that you copied instead of chocking to death.