Reference:
e.g.
template<typename T>
struct C {
C(const T&) {
}
};
C x{"hello"}; // T deduced as char[6]
// with deduction guide
template<typename T> C(T) -> C<T>;
C x{"hello"}; // T deduced as const char*
Non-Template Deduction Guides
template<typename T>
struct S {
T val;
};
S(const char*) -> S<std::string>; // map S<> for string literals to S<std::string>
S s1{"hello"}; // OK, same as: S<std::string> s1{"hello"};
S s2 = {"hello"}; // OK, same as: S<std::string> s2 = {"hello"};
S s3 = S{"hello"}; // OK, both S deduced to be S<std::string>
S s4 = "hello"; // ERROR: can’t initialize aggregates without braces
S s5("hello"); // ERROR: can’t initialize aggregates without braces
Deduction Guides versus Constructors
Deduction guides compete with the constructors of a class.Class template argument deduction uses the constructor/guide that has the highest priority according to overload resolution.
If a constructor and a deduction guide match equally well, the deduction guide is preferred.
template<typename T>
struct C1 {
C1(const T&) {}
};
C1(int) -> C1<long>;
// T deduced as long; the deduction guide is used because it is
// preferred by overload resolution.
C1 x1{42};
// T deduced as char; the constructor is a better match (because
// no type conversion is necessary)
C1 x3{'x'};
Explicit Deduction Guides
template<typename T>
struct S {
T val;
};
explicit S(const char*) -> S<std::string>;
S s1 = {"hello"}; // ERROR (deduction guide ignored and otherwise invalid)
S s2{"hello"}; // OK, same as: S s2{"hello"};
S s3 = S{"hello"}; // OK
S s4 = {S{"hello"}}; // OK
template<typename T>
struct Ptr {
Ptr(T) { std::cout << "Ptr(T)\n"; }
template<typename U>
Ptr(U) { std::cout << "Ptr(U)\n"; }
};
template<typename T>
explicit Ptr(T) -> Ptr<T*>;
Ptr p1{42}; // deduces Ptr due to deduction guide
Ptr p2 = 42; // deduces Ptr due to constructor
int i = 42;
Ptr p3{&i}; // deduces Ptr due to deduction guide
Ptr p4 = &i; // deduces Ptr due to constructor
Deduction Guides for Aggregates
template<typename T>
struct A {
T val;
};
A i1{42}; // ERROR
A s1("hi"); // ERROR
A s2{"hi"}; // ERROR
A s3 = "hi"; // ERROR
A s4 = {"hi"}; // ERROR
// dedution guide
A(const char*) -> A<std::string>;
A s2{"hi"}; // OK
A s4 = {"hi"}; // OK
Note that (as usual for aggregate initialization) you still need curly braces. Otherwise, type T is successfully deduced but the initialization is an error:
In any case, for a type with complicated constructors such as std::vector<> and other STL containers, it is highly recommended not to use class template argument deduction and instead, to specify the element type(s) explicitly.
A s1("hi"); // ERROR: T is string, but no aggregate initialization
A s3 = "hi"; // ERROR: T is string, but no aggregate initialization
std::vector v3{"hi", "world"}; // OK, deduces std::vector
std::vector v4("hi", "world"); // OOPS: fatal runtime error
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.