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
Related
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
It is possible to copy or construct a shared_ptr<Base> from shared_ptr<Deriver> (i.e. shared_ptr<Base> ptr = make_shared<Derived>()). But as we all know, template classes are not convertible to each other, even if the template arguments are. So how can shared_ptrs check if the value of their pointers are convertible and do the conversion if they are?
Yes, specializations of the same class template by default have almost no relationship and are essentially treated like unrelated types. But you can always define implicit conversions between class types by defining converting constructors (To::To(const From&)) and/or conversion functions (From::operator To() const).
So what std::shared_ptr does is define template converting constructors:
namespace std {
template <class T>
class shared_ptr {
public:
template <class Y>
shared_ptr(const shared_ptr<Y>&);
template <class Y>
shared_ptr(shared_ptr<Y>&&);
// ...
};
}
Though the declaration as shown would allow conversions from any shared_ptr to any other, not just when the template argument types are compatible. But the Standard also says about these constructors ([util.smartptr]/5 and [util.smartptr.const]/18 and util.smartptr.const]/21):
For the purposes of subclause [util.smartptr], a pointer type Y* is said to be compatible with a pointer type T* when either Y* is convertible to T* or Y is U[N] and T is cv U[].
The [...] constructor shall not participate in overload resolution unless Y* is compatible with T*.
Although this restriction could be done in any way, including compiler-specific features, most implementations will enforce the restriction using an SFINAE technique (Substitution Failure Is Not An Error). One possible implementation:
#include <cstddef>
#include <type_traits>
namespace std {
template <class Y, class T>
struct __smartptr_compatible
: is_convertible<Y*, T*> {};
template <class U, class V, size_t N>
struct __smartptr_compatible<U[N], V[]>
: bool_constant<is_same_v<remove_cv_t<U>, remove_cv_t<V>> &&
is_convertible_v<U*, V*>> {};
template <class T>
class shared_ptr {
public:
template <class Y, class = enable_if_t<__smartptr_compatible<Y, T>::value>>
shared_ptr(const shared_ptr<Y>&);
template <class Y, class = enable_if_t<__smartptr_compatible<Y, T>::value>>
shared_ptr(shared_ptr<Y>&&);
// ...
};
}
Here the helper template __smartptr_compatible<Y, T> acts as a "trait": it has a static constexpr member value which is true when the types are compatible as defined, or false otherwise. Then std::enable_if is a trait which has a member type called type when its first template argument is true, or does not have a member named type when its first template argument is false, making the type alias std::enable_if_t invalid.
So if template type deduction for either constructor deduces the type Y so that Y* is not compatible with T*, substituting that Y into the enable_if_t default template argument is invalid. Since that happens while substituting a deduced template argument, the effect is just to remove the entire function template from consideration for overload resolution. Sometimes an SFINAE technique is used to force selecting a different overload instead, or as here (most of the time), it can just make the user's code fail to compile. Though in the case of the compile error, it will help that a message appears somewhere in the output that the template was invalid, rather than some error even deeper within internal template code. (Also, an SFINAE setup like this makes it possible for a different template to use its own SFINAE technique to test whether or not a certain template specialization, type-dependent expression, etc. is or isn't valid.)
It works because shared_ptr has (among others) a templated constructor
template<typename U> shared_ptr(U * ptr);
If U* is not convertible to the shared_ptr's contained type then you will get an error buried somewhere in the shared_ptr implementation.
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.
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
Let me present my problem with an example :
template <typename T> class a{
public:
T data;
a():data(T()){}
a(T temp): data(temp) {}
};
So if write in main() like
a(30);
a("String");
So according to the template argument deduction rule , it should be able to generate the first temporary class as a<int>(30) etc
But I the error which says:
missing template arguments before '(' token
so why this happens, this is only true for function template?
Template parameter deduction from arguments only works for functions, never for classes. Until you know the type of the class, i.e. all its template parameters, you don't even know which member functions the class has!
So, you always have to say the template parameters if you want to construct an object directly:
a<int> x(30);
Here's a little thought experiment to expand on the above. Suppose we have
template <typename T> class Foo;
and we are calling Foo::somefunction(x);, where x is some type. You think, well, I declared somefunction() like this:
template <typename T> class Foo
{
static void somefunction(const T & x);
};
so it should be obvious that T is the same type as the type of x. But now imagine I have a specialization:
template <> class Foo<char>
{
static void anotherfunction(double x);
};
The class Foo<char> doesn't even have a function somefunction(), so the expression Foo::somefunction(x) doesn't even get to the stage where I could look up the argument!
The usual way around this is to make a free helper function that constructs your object:
template <typename T> a<T> make_a(const T & x) { return a<T>(x); }
Since this is a function template, its parameters can be deduced:
make_a(30); // type a<int>
make_a("hello"); // type a<char[6]>
The constructor is not a template, its the class which is a template. So when you write a(30), the template argument deduction for the class template cannot be done!
If there exists a constructor template, then the template argument for the templated constructor can be deduced by the compiler. For example here:
template <typename T> class A{
public:
template<typename U>
A(const U &): {} //note : it's a constructor template
};
A<char> obj(30); //U is deduced as int
In the above example, only U can be deduced, you still have to provide T. Its because
U is a template argument for the constructor template. Template argument deduction can be done in this case.
T is a template argument for the class template. Template argument deduction cannot be done here.
You still need to declare a temporary as, for example, a<int>(30).
You cannot infer class template arguments from the arguments to the constructor- unfortunately.
Template type deduction only happens for template functions. You need to specify the parameters for a template class instantiation . You can use a function template to deduce the template parameter and return the appropriate type. In c++0 x you could use auto to hold the instance. Can't easily write example code for you on my phone!