I asked this question earlier where a solution was presented. The solution is great as far as the question is concerned, but now I am confused on how I would define the methods outside of the class i.e. I would like to define the methods in an .inl file. What would be the syntax in this case?
Just to be clear, for a template class, the method definition will be:
template <typename T>
struct Foo
{
Foo();
};
// C-tor definition
template <typename T>
Foo<T>::Foo()
{
}
How would I define methods for the template class with enable_if as one of the parameters?
template <typename Policy, enable_if< is_base<BasePolicy, Policy>::value >::type >
struct Foo
{
Foo();
};
// C-tor definition -- ???
From the looks of it, you want to do something along the lines of this:
template <typename Policy,
typename = typename std::enable_if<std::is_base_of<BasePolicy, Policy>::value>::type >
struct Foo;
template <typename Policy>
struct Foo<Policy> {
Foo();
};
template <typename Policy>
Foo<Policy>::Foo() {
}
This sneakily takes advantage of the default argument in a few places: don't get confused, there is an implicit void sitting in several locations.
Here's how SFINAE can actually work with partial specialization:
template<typename T, typename Sfinae = void>
struct Foo {
/* catch-all primary template */
/* or e.g. leave undefined if you don't need it */
};
template<typename T>
struct Foo<T, typename std::enable_if<std::is_base_of<BasePolicy, T>::value>::type> {
/* matches types derived from BasePolicy */
Foo();
};
The definition for that constructor can then be awkwardly introduced with:
template<typename T>
Foo<T, typename std::enable_if<std::is_base_of<BasePolicy, T>::value>::type>::Foo()
{
/* Phew, we're there */
}
If your compiler supports template aliases (it's a C++11 feature) that then you can cut a lot of the verbosity:
template<typename T>
using EnableIfPolicy = typename std::enable_if<std::is_base_of<BasePolicy, T>::value>::type;
// Somewhat nicer:
template<typename T>
struct Foo<T, EnableIfPolicy<T>> {
Foo();
};
template<typename T>
Foo<T, EnableIfPolicy<T>>::Foo() {}
Note: your original answer referred to utilies from Boost, like boost::enable_if_c and boost::is_base_of. If you're using that instead of std::enable_if and std::is_base_of (which are from C++11), then usage looks like
typename boost::enable_if<boost::is_case_of<BasePolicy, T> >::type
which has the advantage of getting rid of one ::value.
Related
With concepts, C++20 provides nice syntax like
template<typename T>
concept SomeConcept = true; // stuff here
template<typename T>
requires SomeConcept<T>
class Foo;
template<SomeConcept T>
class Foo;
where the two ways of concept restricting the class are equivalent, but the latter is just more concise.
If i now have some template template concept like
template<template<typename> typename T>
concept SomeOtherConcept = true; // stuff here
template<template<typename> typename T>
requires SomeOtherConcept<T>
class Foo;
i do not know the non-verbose (concise / short) syntax for this without an requirement clause, as things like
template<template<typename> SomeotherConcept T>
class Foo;
template<template<SomeOtherConcept> typename T>
class Foo;
did not work, so
What is the correct syntax for declaring such a template template class with a concept restriction to the template template parameter?
What is the correct syntax for declaring such a template template class with a concept restriction to the template template parameter?
The only way to write a constraint that depends on a template template parameter or a non-type template parameter is with a requires-clause. The shorter type-constraint syntax is only available for concepts that constrain types (hence the name type-constraint):
template <typename T> concept Type = true;
template <template <typename...> class Z> concept Template = true;
template <auto V> concept Value = true;
// requires-clause always works
template <typename T> requires Type<T> struct A { };
template <template <typename...> class Z> requires Template<Z> struct B { };
template <auto V> requires Value<V> struct C { };
// type-constraint only for type concepts
template <Type T> struct D { };
// abbreviated function template definitely only for type concepts
void e(Type auto x);
This is a trick that I have used before.
Define a lambda in the primary expression using a noop-like function as shown:
void noop(auto) {}
//...
template<typename T>
concept SomeConcept = true;
/*
template <template<typename>SomeConcept T>
struct Example {};
*/ //does not work
template <template<typename>typename T>
requires requires() {
{
noop(
[]<typename TArg> requires SomeConcept<typename T<TArg>> (){}
)
};
}
struct Example {};
Please tell me why this answer works.
What happened to the enable_if such we can omit it after that? (further usage of Foo struct doesn't need that enable_if in template parameters)
Should not that code be something like this:
Origin version:
template <typename Policy,
typename = typename std::enable_if<std::is_base_of<BasePolicy, Policy>::value>::type >
struct Foo;
template <typename Policy>
struct Foo {
Foo();
};
template <typename Policy>
Foo<Policy>::Foo() {
}
Edited version:
template <typename Policy,
typename = typename std::enable_if<std::is_base_of<BasePolicy, Policy>::value>::type >
struct Foo;
template <typename Policy>
struct Foo<Policy> { // <Policy> added!
Foo();
};
template <typename Policy>
Foo<Policy>::Foo() {
}
This happened:
The author posted working code (<Policy> was present);
There was some discussion in the comments that led the author to edit the code, and he made a mistake (<Policy> was removed);
I rectified the mistake putting back the missing <Policy>.
Can anybody explains why even the edited version works?
When you attempt to instantiate Foo<T>, the declaration with the default template parameters is taken into account by the compiler. The default parameter is evaluated and if std::is_base_of<BasePolicy, Policy>::value is false then enable_if produces a SFINAE-friendly error.
If std::is_base_of<BasePolicy, Policy>::value is true, the partial specialization is chosen.
template <typename Policy>
struct Foo<Policy> {
Foo() { }
};
// is equivalent to
template <typename Policy>
struct Foo<Policy, void> {
Foo() { }
};
The above specializations are equivalent because typename std::enable_if<true>::type is void by default.
In C++17, we have std::void_t, which makes SFINAE look a lot nicer:
template <typename T>
std::void_t<decltype(T::prop)> foo() { /* stuff */ }
The template function will exist only if T::prop exists.
If T::prop exists, the template function foo() would be equivalent to this:
template <typename T>
void foo() { /* stuff */ }
Otherwise, the code is equivalent to not declaring foo() at all.
Is there any generalization of std::void_t for other types in the standard library, such as the following:
template<typename T, typename...>
using generic_t = T;
so that the code below would be valid?
template <typename T>
std::generic_t<int, decltype(T::prop)> foo() { /* stuff */ }
which would be equivalent to
template <typename T>
int foo() { /* stuff */ }
if T::prop exists?
Why do you need such a generalization? void_t is a little special in that it helps you easily write type traits, because you can have a primary with some type defaulted to void and a specialization which uses void_t. For instance:
template <class T, class = void>
struct has_prop : std::false_type { };
template <class T>
struct has_prop<T, std::void_t<decltype(T::prop)>> : std::true_type { };
It's not that there's anything special about void, you just need some agreed upon type between the primary and the specialization.
void_t doesn't make much sense if you're just using it directly in SFINAE though. You could just stick the expression somewhere else:
template <typename T, class = decltype(T::prop)>
void foo() { /* stuff */ }
at which point the return type is totally separate from the condition you're checking anyway, so if you want int:
template <typename T, class = decltype(T::prop)>
int foo() { /* stuff */ }
It probably does not exist. It is not linked in the documentation and therefore I doubt its existence. But you can build such type on your own:
template <class type, class... sfinae_expressions>
using generic_t = type;
I would like to specialize default_delete<_Ty> for all objects derived off of MyBaseClass. This was my best attempt:
template <typename T>
struct default_delete<typename enable_if<is_base_of<MyBaseClass, T>::value, T>::true_type>
{
...
};
The compiler seems to be unable to recognize that my type parameter 'T' is being used, which is understandable given that it is 'downstream' from a 'typename' keyword. Is what I'm trying to accomplish possible?
As 0x499602D2 states in comment, it is not possible without an extra dedicated template parameter. you may use your own deleter as follow:
template <typename T, typename Enable = void>
struct my_default_delete : public std::default_delete<T> {}; // default to std::default_delete<T>
template <typename T>
struct my_default_delete<T, typename std::enable_if<std::is_base_of<MyBaseClass, T>::value>::type>
{
void operator() (T* ) { /* Your specific implementation */ }
};
For structs
<template typename T>
struct Foo
{
...
}
<template typename T>
struct Boo
{
...
}
I want to create function that i will call like
DoSomething<Boo<int>>(x);
DoSomething<Foo<float>>(x);
I tried something like this
<template typename T>
<template typename U>
void DoSomething(T<U>& x)
but it doesn't compile. How do I make template for this kind of function?
Thanks
just do:
template <typename T>
struct Foo
{
};
template <typename T>
struct Boo
{
};
template <typename T>
void DoSomething(T& x) // One parameter is enough, compiler will deduce types automatically
{
}
Boo<int> x;
Foo<float> y;
DoSomething(x); // compiler will generate void DoSomething(Boo<int>& x)
DoSomething(y); // compiler will generate void DoSomething(Foo<float>& x)
Your template declaration is wrong,
<template typename T> // invalid syntax
should be:
template <typename T>
You need to use template template parameter if you want to specify both types:
template <template<typename> class T, typename U>
void DoSomething(T<U>& x)
But depending on what you want to achieve, if you don't need to have both types in your function, simply using a single template parameter should work:
template <typename Y>
void DoSomething(T& x)
<template typename T>
void DoSomething(T& x)
{
// do something
}
You have two choices. For the sake of the examples, consider your Foo template struct and this declaration:
Foo<double> v;
Your first choice is
template <typename T>
void DoSomething1(T& x) { /* ... */ }
// ...
DoSomething1(v);
I strongly believe this is what you need.
However, it might not be the case. Perhaps, you really need to call the function on a type of the form T<U> where T is a template class and U is a type. For instance you might want to instantiate T with an int (that is, create T<int> y;) inside the function's body. Then, your second choice is
template <template <typename> class T, typename U>
void DoSomething2(T<U>& x) { T<int> y; /* ... */ }
// ...
DoSomething2(v);
Unfortunately, this might not yet be enough! If you try,
std::vector<double> w;
// ...
DoSomething2(w);
The last line fails to compile. The reason is that std::vector is a template class that take two type parameters and DoSomething2 expects a template class that takes just one. (Of course one can instantiate std::vector with just one argument because the second one has a default value.) The solution is using a C++11 variadic template template parameter:
template <template <typename, typename...> class T, typename U>
void DoSomething3(T<U>&) { T<int> y; /* ... */ }
// ...
DoSomething3(v);
DoSomething3(w);