I wondering if something similar to this is possible. Basically, I have a templated class that occasionally takes objects of templated classes. I would like to specialize it (or just a member function)for a specific templated class, but the 'generic' form of that class.
template<typename T, typename S>
class SomeRandomClass
{
//put something here
};
template<typename T>
class MyTemplateClass
{
void DoSomething(T & t) {
//...something
}
};
template<>
void MyTemplateClass< SomeRandomClass<???> >::DoSomething(SomeRandomClass<???> & t)
{
//something specialized happens here
}
Replacing the question marks with appropriate types (double, etc) works, but I would like it to remain generic. I don't know what to put there, as any types wouldn't have been defined. I've looked around, and learned about template template parameters, and tried various combinations to no avail. Thanks for the help!
It's possible to specialize the class like this
template <>
template <typename T,typename S>
class MyTemplateClass <SomeRandomClass<T,S> >
{
void DoSomething(SomeRandomClass<T,S>& t) { /* something */ }
};
It's not possible to specialize just the member method, because the specialization is on the class as a whole, and you have to define a new class. You can, however, do
template <>
template <typename T,typename S>
class MyTemplateClass <SomeRandomClass<T,S> >
{
void DoSomething(SomeRandomClass<T,S>& t);
};
template <>
template <typename T,typename S>
void MyTemplateClass<SomeRandomClass<T,S> >::DoSomething(SomeRandomClass<T,S>& t)
{
// something
}
to split up the declaration and definition.
I'm not completely sure why #Ryan Calhoun specialized the way he did but here's a more terse example:
// class we want to specialize with later on
template<typename T, typename S>
struct SomeRandomClass
{
int myInt = 0;
};
// non-specialized class
template<typename T>
struct MyTemplateClass
{
void DoSomething(T & t)
{
std::cout << "Not specialized" << std::endl;
}
};
// specialized class
template<typename T, typename S>
struct MyTemplateClass< SomeRandomClass<T, S> >
{
void DoSomething(SomeRandomClass<T,S> & t)
{
std::cout << "Specialized" << std::endl;
}
};
You can see that you don't need the redundant syntax used in the accepted answer:
template<>
template<typename T, typename S>
Working Demo
Alternative
You can use type_traits and tag-dispatch within your non-specialized class to specialize just the function.
Let's first make a concept for is_random_class:
// concept to test for whether some type is SomeRandomClass<T,S>
template<typename T>
struct is_random_class : std::false_type{};
template<typename T, typename S>
struct is_random_class<SomeRandomClass<T,S>> : std::true_type{};
And then let's declare our MyTemplateClass again, but this time not templated (because we're not specializing) so we'll call it MyNonTemplatedClass:
class MyNonTemplatedClass
{
public:
template<typename T>
void DoSomething(T & t)
{
DoSomethingHelper(t, typename is_random_class<T>::type());
}
// ...
Notice how DoSomething is now templated, and it's actually calling a helper instead of implementing the logic itself?
Let's break down the line:
DoSomethingHelper(t, typename is_random_class<T>::type());
t is as-before; we're passing along the argument of type T&
typename is_random_class<T>::type()
is_random_class<T> is our concept, and since it derives from std::true_type or std::false_type it will have a ::type defined within the class (Google for "type traits")
::type() 'instantiates' the type specified by is_random_class<T>::type. I say it in quotation marks because we're really going to throw that away as we see later
typename is required because the compiler doesn't know that is_random_clas<T>::type actually names a type.
Now we're ready to look at the rest of MyNonTemplatedClass:
private:
//use tag dispatch. If the compiler is smart it won't actually try to instantiate the second param
template<typename T>
void DoSomethingHelper(T&t, std::true_type)
{
std::cout << "Called DoSomething with SomeRandomClass whose myInt member has value " << t.myInt << std::endl;
}
template<typename T>
void DoSomethingHelper(T&t, std::false_type)
{
std::cout << "Called DoSomething with a type that is not SomeRandomClass\n";
}
};
Full Working Demo v2 Here
Notice that our helper functions are named the same, but overloaded on the second parameter's type. We don't give a name to the parameter because we don't need it, and hopefully the compiler will optimize it away while still calling the proper function.
Our concept forces DoSomethingHelper(T&t, std::true_type) only if T is of type SomeRandomClass, and calls the other for any other type.
The benefit of tag dispatch
The main benefit of tag dispatch here is that you don't need to specialize your entire class if you only mean to specialize a single function within that class.
The tag dispatching will happen at compile time, which you wouldn't get if you tried to perform branching on the concept solely within the DoSomething function.
C++17
In C++17, this problem becomes embarrassingly easy using variable templates (C++14) and if constexpr (C++17).
We use our type_trait to create a variable template that will give us a bool value of true if the provided type T is of type SomeRandomClass, and false otherwise:
template<class T>
constexpr bool is_random_class_v = is_random_class<T>::value;
Then, we use it in a if constexpr expression that only compiles the appropriate branch (and discards the other at compile-time, so the check is at compile-time, not run-time):
struct MyNonTemplatedClass
{
template<class T>
void DoSomething(T& t)
{
if constexpr(is_random_class_v<T>)
std::cout << "Called DoSomething with SomeRandomClass whose myInt member has value " << t.myInt << std::endl;
else
std::cout << "Called DoSomething with a type that is not SomeRandomClass\n";
}
};
type-traits were a way to simulate this without needing a class specialization.
Note that is_random_class here is a stand-in for an arbitrary constraint. In general, if you're only checking for a single nontemplated type, prefer a normal overload because it's more efficient on the compiler.
Demo
C++20
In C++20, we can take this a step further and use a constraint instead of if constexpr by using a requires clause on our templated member function. The downside is that we again move back to two functions; one that matches the constraint, and another that doesn't:
struct MyNonTemplatedClass
{
template<class T> requires is_random_class_v<T>
void DoSomething(T& t)
{
std::cout << "Called DoSomething with SomeRandomClass whose myInt member has value " << t.myInt << std::endl;
}
template<class T> requires !is_random_class_v<T>
void DoSomething(T&)
{
std::cout << "Called DoSomething with a type that is not SomeRandomClass\n";
}
};
Demo
Also in C++ 20, we could explicitly encode a concept and use abbreviated template syntax:
template<class T>
concept IsRandomClass = is_random_class_v<T>;
template<class T>
concept IsNotRandomClass = !is_random_class_v<T>;
// ...
template<IsRandomClass T>
void DoSomething(T& t)
{ /*...*/}
template<IsNotRandomClass T>
void DoSomething(T&)
{ /*...*/}
Demo
All you need to do is just template on what you want to keep generic. Taking what you started with:
template<typename T, typename S>
void MyTemplateClass< SomeRandomClass<T,S> >::DoSomething(SomeRandomClass<T,S> & t)
{
//something specialized happens here
}
EDIT:
Alternatively, if you only want to keep part of the SomeRandomClass generic, you could:
template<typename T>
void MyTemplateClass< SomeRandomClass<T,int> >::DoSomething(SomeRandomClass<T,int> & t)
{
//something specialized happens here
}
Edit: this is a correct answer to a different question.
Using the typename T twice confuses the issue a little, because they are compiled separately and are not connected in any way.
You can overload the method to take a templated parameter:
template <typename T>
class MyTemplateClass
{
void DoSomething(T& t) { }
template <typename U,typename V>
void DoSomething(SomeRandomClass<<U,V>& r) { }
};
This maps U and V in the new method to T' and S' in SomeRandomClass. In this setup, either U or V could be the same type as T, but they don't have to be. Depending on your compiler, you ought to be able to do
MyTemplateClass<string> mine;
SomeRandomClass<int,double> random;
// note: nevermind the non-const ref on the string literal here...
mine.DoSomething("hello world");
mine.DoSomething(random);
and the templated call will be selected as the matching overload without having to respecify the types explicitly.
Edit:
To do with with template specialization makes no difference to the overload of DoSomething. If you specialize the class as follows
template <>
class SomeRandomClass <int,double>
{
// something here...
};
then the overload above will eat up this specialized implementation gladly. Just be sure the interfaces of the specialized template and the default template match.
If what you're wanting is to specialize DoSomething to take a specific pair of types for SomeRandomClass then you've already lost generality...that's what specialization is.
If you want to use provide a template struct as a template argument (with intent to use it inside) without specializing it:
Here is an example, that appends a type to a tuple given a template sfinae struct as a template argument:
template<typename Tuple, typename T, template<typename> class /*SFINAEPredicate*/>
struct append_if;
template<typename T, template<typename> class SFINAEPredicate, typename ... Types>
struct append_if<std::tuple<Types...>, T, SFINAEPredicate>
{
using type = typename std::conditional<SFINAEPredicate<T>::value,
std::tuple<Types..., T>, std::tuple<Types...>>::type;
};
// usage
using tuple_with_int = append_if<std::tuple<>, int, std::is_fundamental>;
This can be used since C++11.
Related
I have some templated class types like A,B,C as follows:
template < typename T >
class A{};
template < typename T >
class B{};
template < typename T >
class C{};
And now I want to have a function which accepts in general any type like:
template < typename T>
void Func()
{
std::cout << "Default " << __PRETTY_FUNCTION__ << std::endl;
}
And now I want to specialize the function to only accept one of the given template classes like:
template < typename T>
void Func<A<T>>()
{
std::cout << "All A Types " << __PRETTY_FUNCTION__ << std::endl;
}
Which is not allowed because it is only a partial specialization. OK.
I think concept may help but it feels that I think much too complicated. My solution is:
template < typename T, template <typename > typename OUTER >
bool Check;
template < typename INNER, template < typename > typename OUTER, template < typename> typename T>
constexpr bool Check< T<INNER>, OUTER > = std::is_same_v< OUTER<INNER>, T<INNER>>;
template < typename T >
concept IsA = Check< T, A >;
template < typename T >
concept IsB = Check< T, B >;
template < IsA T >
void Func()
{
std::cout << "All A Types " << __PRETTY_FUNCTION__ << std::endl;
}
template < IsB T >
void Func()
{
std::cout << "All B Types " << __PRETTY_FUNCTION__ << std::endl;
}
int main()
{
Func<A<int>>();
Func<B<int>>();
Func<C<int>>();
}
It feels a bit complicated to me. Can that be simplified? Would be nice if the Check template can be removed. Any idea?
See full example here live
One common workaround would go like this:
template <typename T>
struct FuncImpl {
static void Run() { std::cout << "Default"; }
};
template <typename T>
struct FuncImpl<A<T>> {
static void Run() { std::cout << "Specialized for A<T>"; }
};
template <typename T>
void Func() { FuncImpl<T>::Run(); }
Function templates cannot be partially specialized, but class templates can be; so we just delegate from the former to the latter.
It feels a bit complicated to me. Can that be simplified? Would be nice if the Check template can be removed. Any idea?
Much of complexity and in-elegance is in the fact you need a new concept for every class template. Write a general-purpose and reusable concept, and it is no longer complicated to use.
template <typename T, template <typename...> class TT>
constexpr bool is_instantiation_of_v = false;
template <template <typename...> class TT, typename... TS>
constexpr bool is_instantiation_of_v <TT<TS...>, TT> = true;
template <class C, template<typename...> class TT>
concept instantiation_of = is_instantiation_of_v<C, TT>;
The same principle as yours, except the checker is usable with a template taking any number of type arguments. Meanwhile, the concept accepts the same parameters. The first parameter has a special meaning and is implicitly understood to be the constrained template parameter in the short-hand syntax. The rest (the template template-parameter) must be given explicitly.
How can it be used? Like this
template <instantiation_of<A> T>
int Func()
{
return 'A';
}
template <instantiation_of<B> T>
int Func()
{
return 'B';
}
Got a new class template to constrain over? No problem, this concept works without additional boiler-plate.
template <instantiation_of<D> T>
int Func()
{
return 'D';
}
OP writes:
Yes, would be nice to write some "instant" code directly in the functions template parameter... if possible...
Normally, to determine whether it's a specialization of some given class template, we define a trait ahead of time and then check whether the type satisfies that trait. If you don't want to define anything ahead of time, you have to find a way to perform template argument deduction inline, so you can check whether it succeeds. In C++20, this is straightforward but a bit ugly:
template <typename T>
void Func()
{
std::cout << "unconstrained" << std::endl;
}
template <typename T>
requires requires {
[]<typename U>(const A<U>&){}(std::declval<T>());
}
void Func()
{
std::cout << "constrained" << std::endl;
}
Here, the requires-clause checks whether T can be bound to an argument of type const A<U>& for some deducible U. You can see this example here: https://godbolt.org/z/dTEbaaPvh
This isn't exactly pleasant to read. If you will be using this hack multiple times, I think it's better to just define traits instead. I've answered your question simply to satisfy your curiosity, not to recommend this technique.
The version above will pick the constrained version not only when the template argument is some A<U> but also when it is possibly cv-qualified, possibly ref-qualified, and possibly publicly derived from A<U>. Some tweaks are possible to make the constraint more strict.
I would like to have a templated function like so:
template <typename T>
void ReadHelper(T vector_array[])
{
// some code
}
Where T is some structure. But there are two different versions of this structure:
struct type1 {
float data;
}
struct type2 {
float data;
bool valid;
}
And I would like for ReadHelper to be able to set that valid flag. What is a good way to write two different templated functions to properly handle the two types of structures? I can certainly write overloaded version for all my types, but it is quite tedious. Is there a
way to set the templates properly to do this? SFINAE perhaps?
SFINAE is definitely a solution! I used Templated check for the existence of a class member function? as a reference.
Here's an example of how you might do it. The has_valid type is the important thing; I used it to make a function dispatch, but you could use it other ways too. In your case, you would just call set_valid(vector_array[i]) or whatever from within your read helper.
// SFINAE check for if T has member valid
// note this doesn't check that the member is a bool
template<class T>
class has_valid
{
template<class X>
static std::true_type check(decltype(X::valid));
// Use this version instead if you want to
// check if X::valid is explicitly a bool
/*
template<class X>
static std::true_type check(std::enable_if_t<
std::is_same_v<decltype(X::valid), bool>,
bool
>);
*/
template<class X>
static std::false_type check(...);
public:
using type = decltype(check<T>(true));
constexpr static auto value = type();
};
// Friendly helpers
template<class T>
using has_valid_t = typename has_valid<T>::type;
template<class T>
constexpr static auto has_valid_v = has_valid<T>::value;
// Function dispatcher; call set_valid, which will use has_valid_t to
// dispatch to one of the overloads of dispatch_set_valid, where you can
// either set or not set the value as appropriate
template<class T>
void dispatch_set_valid(T& t, std::false_type)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
template<class T>
void dispatch_set_valid(T& t, std::true_type)
{
t.valid = true;
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
template<class T>
void set_valid(T& t)
{
dispatch_set_valid(t, has_valid_t<T>());
}
See it in action on compiler explorer: https://godbolt.org/z/sqW17WYc6
I was going through the template Aliases from Tour of C++. I couldn't understand the below code and how to use it?
template<typename T>
class Vector {
public:
using value_type = T;
}
Here he is using the value_type as type alias for typename 'T', Why can't we just use the typename T, since we can pass any type to template(i.e. class Vector). What is the need to have alias for template?
template<typename C>
using Value_type = typename C::value_type;
Here how is value_type in the scope of C, i.e. how can we reference value_type with type 'C', since it is inside class "vector"?
does 'value_type' here mean its a Vector?
and 'Value_type' mean int::Vector or string::Vector etc..?
template<typename Container>
void algo(Container &c)
{
Vector<Value_type<Container>> vec;
}
How are these three pieces linked?
Why a member alias?
Consider you use an instantiation of Vector in some other generic code:
template <typename U>
void foo(const U& u);
Vector<int> v;
foo(v);
Then inside foo we would need to go through some hoops to find out that T is int. foo only knows about U which is Vector<int>. If Vector<int> has a value_type alias then it is much simpler to access that:
template <typename U>
void foo(const U& u) {
using value_type = typename U::value_type;
//...
}
Now foo does not need to care that U::value_type actually was the T parameter to Vector and is also fine with a type that is not an instantiation of a template:
struct OtherVector {
using value_type = int;
};
OtherVector ov;
foo(ov);
No member alias: "some hoops"
Using a member alias is the simple way. For the sake of completeness I want to show the complicated way that lets foo infer T from Vector<T>. You'll have to bear with me...
First, note that function templates cannot be partially specialized. Thats why I introduce a level of indirection:
template <typename U>
struct foo_impl {
void operator()(const U& u) {
std::cout << "Hello \n";
}
};
template <typename U>
void foo(const U& u) { foo_impl<U>{}(u); }
Caller will call foo and in the background we can mess around with foo_impl.
For example we can add a partial specilization for Vector<T> where we can directly have access to T:
template <typename T>
struct foo_impl< Vector<T> > {
void operator()(const Vector<T>& v) {
std::cout << "Hello Vector<T>\n";
if constexpr (std::is_same_v<int,T>) {
std::cout << "T == int\n";
}
}
};
Live Example.
However, consider what that means for foo. The foo above is fine with any type that has a value_type alias. Now we have a rather boring general definition (prints "Hello") and a specialization for Vector<T> (that prints more when T==int). Thats quite a restriction if we want foo to also work with a
template <typename T>
struct Bar {};
What can we do? We can provide a more generic specialization that matches also instantiations of Bar:
template <template<class> class A, class T>
struct foo_impl< A<T> > {
void operator()(const A<T>& v) {
std::cout << "Hello A<T>\n";
if constexpr (std::is_same_v<int,T>) {
std::cout << "T == int\n"; // We know what T is when a Vector<T> is passed !!
}
}
};
Live Example
It is using a template tempalte parameter to match any instantiation of a template with a single template parameter.
Are we fine now? Unfortunately no, because suppose we want to get a "value type" from this:
template <typename A,typename B>
struct Moo {};
Suppose by convention the first parameter, A, is the value type we are looking for. Then we need to add an even more generic specialization:
template <template<class...> class A, typename T,typename... Others>
struct foo_impl< A<T,Others...> > {
void operator()(const A<T,Others...>& v) {
std::cout << "Hello A<T>\n";
if constexpr (std::is_same_v<int,T>) {
std::cout << "T == int\n";
}
}
};
Live Example
This will match an instantiation of a template with any number of type parameters and will detect the first template parameter to be T.
Are we fine yet? Unfortunately: Not at all.
The above does not match a
template <typename A, int x>
struct Omg {};
Because it has a non-type template parameter. We could also fix that, but lets stop here. Requiring that a value type is always the first parameter is too restrictive anyhow.
TL;DR
What we actually want is to make foo work with any type that has an associated "value type". And the simple way to do that is that any type that should be passed to foo to supply a member alias called value_type.
Considering class templates, it is possible to provide template specializations for certain types of groups using type traits and dummy enabler template parameters. I've already asked that earlier.
Now, I need the same thing for function templates: I.e., I have a template function and want a specialization for a group of types, for example, all types that are a subtype of a class X. I can express this with type traits like this:
std::enable_if<std::is_base_of<X, T>::value>::type
I thought about doing it this way:
template <typename T, typename ENABLE = void>
void foo(){
//Do something
}
template <typename T>
void foo<T,std::enable_if<std::is_base_of<A, T>::value>::type>(){
//Do something different
}
However, this does not work since partial specialization is not allowed for function templates. So how to do it then? Maybe a default parameter with the type trait as type? But how does the code look like then?
Overloads:
void foo_impl(T, std::false_type);
void foo_impl(T, std::true_type);
foo(T t) { foo_impl(t, std::is_base_of<A, T>()); }
The closest to what you're asking is enable_if on the return type:
template<typename T> typename std::enable_if<std::is_same<T, int>::value>::type foo();
template<typename T> typename std::enable_if<std::is_same<T, char>::value>::type foo();
However, dispatching to a helper function or class is likely to be more readable and efficient.
Helper function:
template<typename T> void foo_helper(std::true_type);
template<typename T> void foo_helper(std::false_type);
template<typename T> void foo() { foo_helper(std::is_same<T, int>()); }
Helper class:
template<typename T, bool = std::is_same<T, int>::value> struct foo_helper {};
template<typename T> struct foo_helper<T, true> { static void foo(); };
template<typename T> struct foo_helper<T, false> { static void foo(); };
template<typename T> void foo() { foo_helper<T>::foo(); }
Do the actual implementation (partial specializations etc..) in class templates and write a small wrapper template function that does nothing but call a static function in your class templates.
Tried a few things and finally came up with the correct syntax myself - sorry for asking. I didn't know that enable_if has a second parameter. By using this parameter and a default value, it is possible.
Here is the answer
template<typename T>
void foo(typename std::enable_if<std::is_base_of<A, T>::value,int>::type ENABLER = 0){
std::cout << "T is a subclass of A!";
}
template<typename T>
void foo(typename std::enable_if<!std::is_base_of<A, T>::value,int>::type ENABLER = 0){
std::cout << "T is NOT a subclass of A";
}
Possibly easy to solve, but its hard to find a solution to this:
Is it possible to (partially) specialize for a whole set of types?
In the example "Foo" should be partially specialized for (T,int) and (T,double) with only one template definition.
What I can do is define a specialisation for (T,int). See below. But, it should be for (T,int) and (T,double) with only one function definition (no code doubling).
template <typename T,typename T2>
struct Foo
{
static inline void apply(T a, T2 b)
{
cout << "we are in the generic template definition" << endl;
}
};
// partial (T,*)
template <typename T>
struct Foo<T, int > // here something needed like T2=(int, double)
{
static inline void apply(T a, T2 b)
{
cout << "we are in the partial specialisation for (T,int)" << endl;
}
};
Any ideas how to partially specialize this for (T,int) and (T,double) with one template definition?
If I understood your question correctly, then you can write a base class template and derive from it, as illustrated below:
template <typename T, typename U>
struct Foo_Base
{
static inline void apply(T a)
{
cout << "we are in the partial specialisation Foo_Base(T)" << endl;
}
};
template <typename T>
struct Foo<T, int> : Foo_Base<T, int> {};
template <typename T>
struct Foo<T, double> : Foo_Base<T, double> {};
Although its not one template definition (as you asked for), but you can avoid the code duplication.
Demo : http://www.ideone.com/s4anA
I believe you could do this using Boost's enable_if to enable the partial specialisation for just the types you want. Section 3.1 shows how, and gives this example:
template <class T, class Enable = void>
class A { ... };
template <class T>
class A<T, typename enable_if<is_integral<T> >::type> { ... };