How can a struct inherits itself? - c++

template <bool condition>
struct when;
template <typename It, typename = void>
struct at_impl : at_impl<It, when<true>> { };
struct at_t {
template <typename Xs, typename N>
constexpr decltype(auto) operator()(Xs&& xs, N const& n) const;
};
constexpr at_t at{};
int main()
{
}
How could this program compiled? How can a struct inherits itself?!
I don't know what's going on here. Is this a new feture in c++?

How can a struct inherits itself?
No. A struct can not inherit itself.
A struct that is an instance of a struct template can inherit another instance of the same template, as long as the parent is instantiated with different template arguments †.
at_impl is not a struct; it is a template.at_impl<It, when<true>> is an instance of the template, and it is a struct.
Note that the parent struct must be complete at the time the derived struct is instantiated. This is possible if the parent is a specialization. Your example shows neither the definition of at_impl<It, when<true>> specialization, nor any instantiation of at_impl.
This is analogous to functions. A function can call itself recursively, but the function arguments must change. If a function calls itself with the same arguments, then the recursion can never terminate. A function with no arguments can not be recursive ††.
Now, a template has arguments and is analogous to a function with parameters. A type has no template arguments and is analogous to a function with no parameters. Instantiating a template results in a type and is analogous to a function call.
† This is a necessary condition for the termination of the recursion, but not sufficient.
†† Unless the function depends on global state, but from abstract point of view, we must consider global state as an implicit argument in this context.

at_impl is a struct/class template, from which a struct/class is generated.
Different template arguments to at_impl generate different structs. Inheriting from a different struct/class is allowed.

Related

Function pointer definition inside a class template based on the template variable arguments

using FuncDef = void(int a, int b);
template <typename R, typename... Args>
class WrongFunction {
public:
void F1(R(*Fn)(Args...)) {}//error: C2091 function returns function
};
template <typename T> class Function;
template <typename R, typename... Args>
class Function<R(Args...)> {
public:
void F1(R(*Fn)(Args...)) {}
};
void test() {
WrongFunction<FuncDef> errfunc;//trigger the above compilation error
Function<FuncDef> func;//no problem
}
(1) Why Function works but WrongFunction doesn't (check the compilation error in the comment)? What is the theory behind (e.g. something from cppreference which contains every details about C++)?
(2) (optional) Is there a way to make WrongFunction work but not in the form as Function?
The follow class template:
template <typename R, typename... Args>
class WrongFunction {
public:
void F1(R(*Fn)(Args...)) {}//error: C2091 function returns function
};
defines a template parameter API which expects:
a return type R, and
a variadic number of arguments (of possible different types) Args.
Now, a template parameter pack may be empty, which hides your actual error here. In the instantiation of of the WrongTemplate class template:
WrongFunction<FuncDef> errfunc;
you provide only a single template argument, which matches the first template parameter of the class template:
FuncDef is used as argument for R in WrongFunction
whereas you are providing no argument for template parameter pack.
Thus, the compilers' error message is quite telling: you are instantiating the WrongFunction class template with a template argument provided for the template parameter R, which semantically signifies a return type, but with a function type argument. Meaning, in the associated specialization, R is a function type;
void F1(R(*Fn)(Args...)) {}
// resolves to, for WrongFunction<FuncDef> specialization
void F1( (void)(*)(int, int) (*Fn)() ) {}
// ^^^^^^^^^^^^^^^^^^^ <- R
thus defining a function parameter that is declared to have the type "pointer to function (named Fn) with zero arguments that return a pointer to function with two arguments that return void". This is illegal, thus the compiler error.
In your other class template, you leverage specialization, constructing the primary class template API to have a single type template parameter, semantically intended to be provided arguments that are of type "pointer to function", as the the only partial specialization (as the primary template is not defined) is specifically partially specialized for this kind of argument.
(2) (optional) Is there a way to make WrongFunction work but not in the form as Function?
The template parameter API of WrongFunction expects the client to explicitly provide the return type for the intended function pointer (of the member function) and the argument types by separate template arguments. It basically does not rely on deduction. Your second approach with specialization is the common one, and instead of fixing the likely ill-designed WrongFunction, I will note a similar but slightly different design of Function, which embeds a function pointer into its type instead. Thus could be useful if the member function of a given specialization should only use delegation to a specific function, rather than allowing dynamic dispatch delegation via function pointers of specific function pointer type (as function parameter to the member function).
#include <utility>
template <auto> class Function;
template <typename R, typename... Args, R (*Fn)(Args...)>
class Function<Fn> {
public:
template <typename... FnArgs /* optionally SFINAE that FnArgs is Args */>
void F1(FnArgs &&... args) {
Fn(std::forward<FnArgs>(args)...);
}
};
void f(int a, int b) {}
int main() {
Function<f> func;
func.F1(1, 2);
}

Calling template constructor in a non-template class from derived class [duplicate]

Can you tell me how to invoke template constructor explicitly (in initializer list)?
for example:
struct T {
template<class> T();
};
struct U {
U() : t<void>() {} //does not work
T t;
};
thanks
It's not possible. The Standard also has a note on this at 14.8.1/7
[Note: because the explicit template argument list follows the function template name, and because conversion member function templates and constructor member function templates are called without using a function name, there is no way to provide an explicit template argument list for these function templates. ]
Explanation: This says: Template arguments are passed in angle brackets after a function template name, such as std::make_pair<int, bool>. And constructors don't have a name of their own, but they abuse their class names in various contexts (so U<int>() means: Pass <int> to the class template U, and construct an object by calling the default constructor without arguments). Therefore, one cannot pass template arguments to constructors.
In your case, you are trying to pass template arguments in a member initializer. In that case, there's even more of a problem: It will attempt to parse and interpret t<void> as a base-class type and thinks you want to call the default constructor of a base class. This will fail, of course.
If you can live with it, you can work it around
struct T {
template<class U> T(identity<U>);
};
struct U {
U() : t(identity<void>()) {}
T t;
};
Given identity like it's defined in boost
template<typename T> struct identity { typedef T type; };
Within C++20 you can use std::type_identity as identity type.
https://en.cppreference.com/w/cpp/types/type_identity

Deducing pointer-to-member template arguments

Consider classes with member variables, like these:
struct A {
int a;
char b;
};
struct B {
double c;
bool d;
};
Is it possible to declare a template class that accepts as its template
argument a pointer-to-member-object to any one of the members declared
in the above classes?
A class that accepts a generic pointer-to-member-object could be
declared and used as follows:
template<typename Class, typename Type, Type (Class::*Member)>
struct Magic
{ };
// Usage:
typedef Magic<A, int, &A::a> MagicWithA_a;
Unfortunately it is quite cumbersome having to pass in the Class and
Type template arguments every time to make the final pointer work.
Is there any way to have these arguments deduced by partial specialization,
for example? That is, how can the Magic class be declared to make the
below definitions work?
typedef Magic<&B::c> MagicWithB_c;
typedef Magic<&A::b> MagicWithA_b;
With C++17 you can use auto non-type template parameter:
template<auto p_member>
struct Magic
{ };
Before C++17 only the longer variant that you've implemented would work.
You can shorten it somewhat with specializations, yes. And if you don't mind resorting to macros you can have almost the syntax you want with c++11. First, a primary template specialization:
template<typename T, T pm>
struct MagicImpl; // Undefined for most types
Then a partial specialization for pointers to members, where we can freely add the parameters we wish to be deduced:
template<class Class, typename Type>
struct MagicImpl<Type Class::*, Type (Class::*Member)> {
};
And finally, we need to employ decltype to get the pointer to member type out of the pointer-to-member expression, which we hide behind the aforementioned macro:
#define MAGIC(...) MagicImpl<decltype(__VA_ARGS__), __VA_ARGS__>
And you can use it as follows:
typedef MAGIC(&B::c) MagicWithB_c;
typedef MAGIC(&A::b) MagicWithA_b;

Initialize member with template constructor [duplicate]

Can you tell me how to invoke template constructor explicitly (in initializer list)?
for example:
struct T {
template<class> T();
};
struct U {
U() : t<void>() {} //does not work
T t;
};
thanks
It's not possible. The Standard also has a note on this at 14.8.1/7
[Note: because the explicit template argument list follows the function template name, and because conversion member function templates and constructor member function templates are called without using a function name, there is no way to provide an explicit template argument list for these function templates. ]
Explanation: This says: Template arguments are passed in angle brackets after a function template name, such as std::make_pair<int, bool>. And constructors don't have a name of their own, but they abuse their class names in various contexts (so U<int>() means: Pass <int> to the class template U, and construct an object by calling the default constructor without arguments). Therefore, one cannot pass template arguments to constructors.
In your case, you are trying to pass template arguments in a member initializer. In that case, there's even more of a problem: It will attempt to parse and interpret t<void> as a base-class type and thinks you want to call the default constructor of a base class. This will fail, of course.
If you can live with it, you can work it around
struct T {
template<class U> T(identity<U>);
};
struct U {
U() : t(identity<void>()) {}
T t;
};
Given identity like it's defined in boost
template<typename T> struct identity { typedef T type; };
Within C++20 you can use std::type_identity as identity type.
https://en.cppreference.com/w/cpp/types/type_identity

C++ invoke explicit template constructor

Can you tell me how to invoke template constructor explicitly (in initializer list)?
for example:
struct T {
template<class> T();
};
struct U {
U() : t<void>() {} //does not work
T t;
};
thanks
It's not possible. The Standard also has a note on this at 14.8.1/7
[Note: because the explicit template argument list follows the function template name, and because conversion member function templates and constructor member function templates are called without using a function name, there is no way to provide an explicit template argument list for these function templates. ]
Explanation: This says: Template arguments are passed in angle brackets after a function template name, such as std::make_pair<int, bool>. And constructors don't have a name of their own, but they abuse their class names in various contexts (so U<int>() means: Pass <int> to the class template U, and construct an object by calling the default constructor without arguments). Therefore, one cannot pass template arguments to constructors.
In your case, you are trying to pass template arguments in a member initializer. In that case, there's even more of a problem: It will attempt to parse and interpret t<void> as a base-class type and thinks you want to call the default constructor of a base class. This will fail, of course.
If you can live with it, you can work it around
struct T {
template<class U> T(identity<U>);
};
struct U {
U() : t(identity<void>()) {}
T t;
};
Given identity like it's defined in boost
template<typename T> struct identity { typedef T type; };
Within C++20 you can use std::type_identity as identity type.
https://en.cppreference.com/w/cpp/types/type_identity