I'm currently creating some utilities for my projects, and I came up with the idea to replicate the C# Action class in C++. As you can see in the C# documentation, the Action class can have different "overloads" with templates. It has Action, Action<T1>, Action<T1, T2\>, etc.
Is it possible to overload classes like this in C++? Or, is there any workaround?
This is an example of "pseudocode", C++ throws a syntax error with this:
class Action
{
// Code
};
template<class T1>
class Action
{
// Code
};
template<class T1, class T2>
class Action
{
// Code
};
// etc...
So that you can call different kinds of classes depending if you input a template or not, like this:
int main()
{
Action a1;
Action<int> a2;
Action<int, float> a3;
// etc...
return 0;
}
I tried various things, such as:
template<T1, T2>
class Action {};
template<T1, T2>
class Action<T1.> {};
template<T1, T2>
class Action<T1, T2> {};
But this does not work.
No, classes can't be overloaded. Action in the scope can be either a single non-templated class or a single class template with a given template head (not different ones).
But, a given class template can be specialized for certain template arguments and there are variadic templates since C++11 which accept an arbitrary number of template arguments:
template<typename... Ts>
class Action { /* generic case */ };
This allows for a2 and a3 and via explicit or partial specialization they can be specialized for e.g. one or two template arguments:
template<typename T1>
class Action<T1> { /* one template argument */ };
template<typename T1, typename T2>
class Action<T1, T2> { /* two template arguments */ };
a1 can also work since C++17 via class template argument deduction (CTAD) depending on which constructors the primary class template has and/or what deduction guides are declared.
I don't have enough knowledge of C# or context to know whether this is a useful approach to take for your underlying problem though.
Also, as a side note: class and typename when introducing template parameters in the template head are synonymous. Choose class if you prefer that. There is no difference.
Related
I'm new in advanced usage of templates and concepts, so here is a liitle bit complex problem:
I have some Traits concept of many traits for each of Source classes:
template<typename _Traits>
concept Traits = requires
{
std::same_as<std::decay_t<decltype(_Traits::token)>, std::string_view>;
};
I have some template class that uses this concept to handle object_one with various traits (for example, half of Source classes returns object_one):
template <concepts::Traits _Traits>
class Object_one_handler final
{
static std::string handle_object(const object_one& obj) {/*...*/}
};
Then I have Objects_handlers concept of handlers for various objects from set {object_one, object_two, object_three} from various Sources with their Traits:
template<template <concepts::Traits _Traits> class _Objects_handlers, typename _Object>
concept Objects_handlers = requires(const _Object& obj)
{
// has handle_object method
{ _Objects_handlers<???????>::handle_object(obj) } -> std::same_as<std::string>;
};
Finally, I creating some database with specified as template parameter Object_handler:
template<concepts::Objects_handlers _handler>
class database
{...};
(Actually all of concepts have additional requirements, but it doesn't matter here)
So problem is in last Objects_handlers concept:
template<template <concepts::Traits _Traits> class _Objects_handlers, typename _Object>
concept Objects_handlers = requires(const _Object& obj)
{
// has handle_object method
{ _Objects_handlers<???????>::handle_object(obj) } -> std::same_as<std::string>;
^^^^^^^
};
I can't check _Objects_handlers method without template parameter (obviously) and I can't properly set the template parameter which must be one of Traits.
How can I do that?
And actually it may be problem in usage of Objects_handlers in template of database class, so one more question: how to use it?
P.S. It can be XY problem or not about concepts at all... Maybe composition with strategy pattern will be more usefull, but still want try to create this maybe useless, but workable concept.
Let's reduce this problem a lot.
template <typename T>
struct C {
void f();
};
Now, your goal is to write a concept that takes any class template (e.g. C) and checks that every specialization of it has a nullary member function named f.
template <template <typename> class Z>
concept HasF = requires (Z<???> z) {
z.f();
};
The problem is - class templates in C++ just don't work like this. Even for a particular class template, like C, you can't require that every specialization has f. There's no way to ensure that like somebody, somewhere, didn't add:
template <> struct C<std::vector<std::list<std::deque<int>>>> { };
All you can do is check that a specific type has a nullary member function named f. And that's:
template <typename T>
concept HasF = requires (T t) { t.f(); };
The type-constraint syntax, template <Concept T>, is only available for concepts that constrain types, not concepts that constrain templates or values.
I want to use partial template specialization but it seems I am missing something.
Here is what I've tried:
template<class T1, class T2>
class AClass {};
template<class T>
class AClass<T, T> {}; // specialized class.
AClass<int,float> aClassIntFloat; // works just fine
AClass<int, int> aClassIntInt; // works just fine
AClass<int> specializedIntClass; //"error: wrong number of template arguments (1, should be 2)"
What am I missing?
First of all, you have already successfully defined a partial specialistation:
AClass<int, int> will instantiate class AClass<T, T> with T=int
AClass<int,float> will instantiate class AClass<T1, T2> with T1=int and T2=float
You can easily check this by adding a public test method and invoking it for aClassIntFloat and aClassIntInt (online demo). You'll find out that the partial specialization defined for two identical types will be used.
You can also make another partial specialization, for example:
template<class T2>
class AClass<double, T2> { public: void test(){cout<<"ADT2"<<endl;}};
AClass<double, int> aClassDoubleInt; // works also fine
A partial specialization lets you fix some parameters but not all. But in the end, your template requires two parameters, and you'll have to provide two parameters. The only question is which specialization if any gets instantiated (online demo).
I am trying to use a member type of a template class, which does not depend on any template parameters of the template class. I would like to keep the type as the member type due to its logic, but I do not want to specify the unnecessary template parameters of the class whenever I want to use the member type outside the class.
Consider the following:
class Dummy { };
// Template class
template<typename T>
class A {
public:
template<typename T2>
class MemberType : public T2 {
public:
T2 t2;
};
};
int main()
{
typename A<Dummy>::template MemberType<Dummy> m1; // okay
typename A::template MemberType<Dummy> m2; // not okay!
return 0;
}
I got the following compiler error when I try to compile using g++:
error: ‘template<class T> class A’ used without template parameters
typename A::template MemberType<Dummy> m2; // not okay!
Is there any workaround for this?
I am trying to use a member type of a template class, which does not
depend on any template parameters of the template class.
As a nested type within class A<T>, MemberType does depend on the template parameter T.
i.e. A<T>::MemberType<T2> and A<U>::MemberType<T2> are distinct classes.
What you want to do is not possible. A template is just a template. There is very little you can do with it before actually instantiating it for a concrete type. There could be a specialization for A that has no nested MemberType at all.
I would like to keep the type as the member type due to its logic,
[...]
...but it seems the logic is something else: The MemberType does not depend on A, hence it should not be part of a template that depends on A.
Sloppy speaking template<typename T> can be read as "everything that follows depends on T". Even if you think it does not, there could always be a specialization that changes anything inside A. If you want MemberType to not depend on T then declare it outside A.
Everything in a template is dependent on the parameter(s) - meaning a template-specialization might not even have class MemberType.
But you can make a default parameter - you still need to write <> though (but you can omit template usually - even typename, but I left that):
class Dummy { };
// Template class
template <class T = void>
class A {
public:
template<typename T2>
class MemberType : public T2 {
public:
T2 t2;
};
};
int main()
{
typename A<Dummy>::MemberType<Dummy> m1; // okay
typename A<>::MemberType<Dummy> m2; // also ok
return 0;
}
As others have pointed out, this somewhat looks like an anti-pattern though - since the inner type is not dependent on the parameter of the outer template class.
Is there any workaround for this?
MemberType is a type dependent from a template parameter so, necessarily, you have to pass through the containing template a template parameter to define it
typename A<SomeType>::template MemberType<AnotherType> m2;
Taking in count that your not interested in external SomeType parameter, the best workaround I can imagine is the use of a using as follows (or something similar)
template <typename T>
using MemberType_t = typename A<T>::template MemberType<T>;
to reduce typewriting.
The following is a full compiling simplified example
#include <type_traits>
class Dummy { };
template <typename>
struct A
{
template <typename T2>
struct MemberType : public T2
{ T2 t2; };
};
template <typename T>
using MemberType_t = typename A<T>::template MemberType<T>;
int main ()
{
typename A<Dummy>::template MemberType<Dummy> m1;
MemberType_t<Dummy> m2; // compile
static_assert( std::is_same<decltype(m1), decltype(m2)>::value, "!" );
}
I'm working in a simulator. This simulator receives as input 2 kind of models, behavioural, and structural.
A behavioural model, is some any class that provides a few required functions and requires a template parameter "TIME".
A structural model, is a set of models (behavioural or structural) and a list of interactions between them. A structural model, does not provide behaviour, and as such does not require the parameter for TIME.
Example of behavioural model:
template<typename TIME>
struct B {...};
Example of Structural model:
template<typename connections, typename Ms>
struct S {
template<typename TIME>
using models=typename Ms::template type<TIME>;
...
};
The main problem is the "models" here.
As it is listed there, every model gets a TIME template parameter, and I can get as many B models as I want. However, I cannot pass a S model to it.
My implementation of a models_tuple is the following
template<template<typename TIME> class... Ms>
struct models_tuple {
template<typename T>
using type=std::tuple<Ms<T>...>;
};
Is there any way that I can make the tuple receive both, classes with a Template parameter (Time) and others without it?
I'm using static_assert for validating that classes are covering the requirements of implementing the functions.
You can't have a mix of template template parameters and template type parameters. But you can wrap the former into a type.
template<template<class> class B>
struct wrap {};
Then, add the time, but only if it's the wrapper for the first kind of types:
template<class W, class>
struct maybe_apply_time { using type = W; };
template<class T, template<class> class B>
struct maybe_apply_time<wrap<B>, T> { using type = B<T>; };
template<class... Ms>
struct models_tuple {
template<typename T>
using type=std::tuple<typename maybe_apply_time<Ms, T>::type...>;
};
And uses it as models_tuple<wrap<B>, S</*...*/> /*, etc. */>.
In C++ there are 2 template types (to my knowledge): template classes and template functions. Why is it not possible to have a template of template? (be it class, or function, or other template). Has it ever been considered in standards? Does it break C++ syntax/spirit in a way?
I know it may sound crazy, and it's easy to get around.
What is possible with C++:
template<bool b>
class TemplateDependingOnBool
{
public:
template<typename T>
class TheTemplateWeWant{};
}
What would be great:
template<bool b>
template<typename T>
class TheTemplateWeWant{};
and call it in a policy-based style (that's where it's really interesting):
template<typename T, template<typename> class ThePolicy = TheTemplateWeWant<true> >
class Foo {};
The way it's possible to do now is to use:
template<typename T,
template<typename> class ThePolicy = TemplateDependingOnBool<true>::TheTemplateWeWant >
class Foo{};
which is not very elegant.
EDIT:
I know I can template on 2 parameters. The goal is to use the underlying template class (the templated template) as something by itself, be it in a template alias or a template template parameter (as shown in my example).
Policy-based design is a reference to Andrei Alexandrescu's Modern C++ Design, which is the main reason why the feature I'm asking might be useful (because templates are used as template parameters).
With C++11, you're wrong in assuming only two types of templates. There are also type aliases which allow
template <bool b, typename T>
class TheTemplateWeWant { ... };
template<typename T>
using ThePolicy = TheTemplateWeWant<true, T>
If I'm understanding what you're asking correctly (and I'm not entirely clear on your question), then you could write your template taking two parameters:
template <bool b, typename T>
class TheTemplateWeWant { ... };
add a metafunction to partially apply the bool:
template <bool b>
struct PartiallyWant {
template <typename T>
using type = TheTemplateWeWant<b, T>;
};
and then pass that as your policy:
template<typename T,
template<typename> class ThePolicy = PartiallyWant<true>::type >
class Foo { ... };
Foo<char, PartiallyWant<false>::type> foo;
So why not just layer the templates like you propose? The simple answer is that there's no reason to. If TheTemplateWeWant has two template parameters (bool b and typename T, regardless of whether it's an "inner" class or not), then we should express it as such. And if we want to only apply one type or the other, that's something that has fewer use-cases than a general template while also being solvable with just a few lines of boilerplate. Additionally, what if we had such a feature, and now I want to partially apply the T instead of the b? With a few lines of boilerplate I can again accomplish the same thing, but with the layering this would be impossible.
As far as i know you cand you simply that, and it works just as you want - class templated with 2 parameters.
template<bool b, typename T>
class TheTemplateWeWant{}; //valid in C++
What you're describing is partial binding of template parameters, just like std::bind can turn a binary function into a unary function.
For metaprogramming madness, there's Boost.MPL. They do have a template boost::mpl::bind.