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.
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 {};
I am attempting to specialize a class on a type s.t. it ignores the constness of the given type. In this case, the type is a template template parameter:
template <class T, typename Enable = void>
struct bar
{
bar()
{
static_assert(!std::is_same<T,T>::value, "no implementation of bar for type T");
}
};
template <template <typename> class FooType, class T>
struct bar<FooType<T>, typename std::enable_if<std::is_same<typename std::remove_cv<FooType<T>>::type, foo<T>>::value>::type>
{};
The above code complains in both GCC 4.8.4 and clang 5.0 (with -std=c++11) that bar is undefined when used with a class matching the template parameterization of FooType. Even if I remove the sfinae parameter, the specialization is still unable to be found.
An example of this issue can be found here: https://godbolt.org/g/Cjci9C.
In the above example, the specialization's constructor has a static assert that goes unfound when used with a const FooType, even when the sfinae parameter is hard-coded to void. When used with a non-const FooType all works as expected.
Can someone please provide an explanation as to why the constness prohibits type deduction (matching?) in this context.
EDIT (Updated Code):
Here is a fully compile-able snippet. I tried to capture the minimum example in this snippet. The original link has been updated to reflect this example.
#include <assert.h>
#include <type_traits>
template <class T>
struct foo {};
template <class T, typename Enable = void>
struct bar
{
bar()
{
static_assert(!std::is_same<T,T>::value, "no implementation of bar for type T");
}
};
template <template <typename> class FooType, class T>
struct bar<FooType<T>, typename std::enable_if<std::is_same<typename std::remove_cv<FooType<T>>::type, foo<T>>::value>::type>
{};
int main()
{
bar<foo<int>> mut_foo; // This is fine.
// bar<const foo<int>> const_foo; // Error. No implementation found.
}
Removing the comment on the 2nd line of main triggers the static assert. I have also tried std::decay, and std::remove_const with no success.
EDIT (Non-duplicate Justification):
While the linked problem does ask a similar problem, it does not require the use of template template parameters. It also only provides a technique for solving the problem and does not justify why the given code snippet does not work. Interestingly that technique does not seem to work with template template parameters, since substituting the following snippet into the above example results in the same error:
template <template <typename> class FooType, class T>
struct bar<FooType<T>,
typename std::enable_if<std::is_same<FooType<T>, foo<T>>::value || std::is_same<FooType<T>, const foo<T>>::value>::type>
{};
const foo<int> doesn't match FooType<T>,
it would match const FooType<T> or T (or const T).
After specialization match, you might add SFINAE:
So, in your case, you may do
template <typename T> struct is_foo : std::false_type {};
template <typename T> struct is_foo<foo<T>> : std::true_type {};
template <class T>
struct bar<T,
typename std::enable_if<is_foo<typename std::remove_cv<T>::type>::value>::type>
{};
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 have a problem in separating the implementations of an inner class while having partial specializations. Here is a sample code that illustrate my problem:
#include <type_traits>
template <typename T>
using enable_if_copyable = std::enable_if_t<std::is_copy_constructible<T>::value>;
template <typename T>
using enable_if_not_copyable = std::enable_if_t<!std::is_copy_constructible<T>::value>;
template <typename T, typename Enabled=void>
struct Foo;
template <typename T>
struct Foo<T, enable_if_copyable<T>>
{
struct Bar
{
Bar();
};
};
template <typename T>
struct Foo<T, enable_if_not_copyable<T>> {
struct Bar
{
Bar();
};
};
template <>
struct Foo<void,void>
{
struct Bar
{
Bar();
//Bar() {} This compiles, but it is not what I want.
};
};
template <typename T>
Foo<T, enable_if_copyable<T>>::Bar::Bar()
{}
template <typename T>
Foo<T, enable_if_not_copyable<T>>::Bar::Bar()
{}
template <>
Foo<void, void>::Bar::Bar() // this does not compile
{}
int main() {
Foo<int>::Bar b;
Foo<void>::Bar v;
}
Because of dependencies I have to implement the c'tors of Bar outside their declaration.
My problem is that all compiler (Clang, gcc, Visual Studio 2015) complain about the implementation of Foo<void, void>::Bar::Bar() {} outside of the declaration of class Foo<void, void>. If I implement the c'tor of Bar inside the specialization on void, I don't have any problem.
Is this is not doable or is there one who could help me to spot my problem?
Many thanks in advance!
Try deleting the template<>; i mean:
// template <>
Foo<void, void>::Bar::Bar() // now compile
{}
See this page for further details.
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.