Reference:
Template Normal Programming, Part 1 - Arthur O'Dwyer - CppCon 2016.pdf
Template Normal Programming, Part 2 - Arthur O'Dwyer - CppCon 2016.pdf
Type deduction in a nutshell:
Any template parameters that were explicitly specified by the caller
are fixed as whatever the caller said they were;
they don’t participate any further in deduction.
Each function parameter may contribute (or not) to the deduction of
each remaining template parameter (or not).
Deductions are carried out in parallel; they don’t cross-talk with each other.
At the end of this process, the compiler checks to make sure that each
template parameter (that wasn’t specified by the caller) has been
deduced at least once and that all deductions agree with each other.
Furthermore, any function parameter that does contribute to deduction must match its function argument type exactly.
AWARE: (reference: https://en.cppreference.com/w/cpp/language/template_argument_deduction)
Deducing T& (not T&&):
The compiler basically tries to deduce T by stripping all the reference
qualifiers (but not the cv-qualifiers) off of the argument type, and then reintroducing a single '&' qualifier if it helps make a match via reference collapsing.
Template Normal Programming, Part 1 - Arthur O'Dwyer - CppCon 2016.pdf
Template Normal Programming, Part 2 - Arthur O'Dwyer - CppCon 2016.pdf
Type deduction in a nutshell:
Any template parameters that were explicitly specified by the caller
are fixed as whatever the caller said they were;
they don’t participate any further in deduction.
Each function parameter may contribute (or not) to the deduction of
each remaining template parameter (or not).
Deductions are carried out in parallel; they don’t cross-talk with each other.
At the end of this process, the compiler checks to make sure that each
template parameter (that wasn’t specified by the caller) has been
deduced at least once and that all deductions agree with each other.
Furthermore, any function parameter that does contribute to deduction must match its function argument type exactly.
AWARE: (reference: https://en.cppreference.com/w/cpp/language/template_argument_deduction)
Deducing T& (not T&&):
The compiler basically tries to deduce T by stripping all the reference
qualifiers (but not the cv-qualifiers) off of the argument type, and then reintroducing a single '&' qualifier if it helps make a match via reference collapsing.
(for l-value; if it's r-value, T as it is.)
In other words: You can bind a parameter of “non-volatile const lvalue reference” type to an argument of “rvalue” type.
However, this rule doesn’t interact with the type deduction rules!
The compiler won’t insert const qualifiers into its deduced T just to make the binding come out right.
-
Lambda:
If you absolutely need the function-pointer conversion to happen,
add a unary +. (Except on MSVC.)
i.e:
msvc:
https://blogs.msdn.microsoft.com/oldnewthing/20150220-00/?p=44623
-
Partial specialization(Variable template):
Ref: variable_template
N4606: “...a standard conversion sequence cannot be formed if it requires binding an
lvalue reference other than a reference to a non-volatile const type to an rvalue or
binding an rvalue reference to an lvalue...”
In other words: You can bind a parameter of “non-volatile const lvalue reference” type to an argument of “rvalue” type.
However, this rule doesn’t interact with the type deduction rules!
The compiler won’t insert const qualifiers into its deduced T just to make the binding come out right.
-
template<typename T>
void f(T& t)
{
puts(__PRETTY_FUNCTION__);
}
int main() {
int i = 42;
f(static_cast<int&>(i)); // [with T=int]
f(static_cast<int&&>(i)); // ERROR (T=int)
f(static_cast<const int&>(i)); // [with T=const int]
f(static_cast<const int&&>(i)); // [with T=const int] (!)
}
-Lambda:
If you absolutely need the function-pointer conversion to happen,
add a unary +. (Except on MSVC.)
i.e:
msvc:
https://blogs.msdn.microsoft.com/oldnewthing/20150220-00/?p=44623
-
template<typename R, typename A>
void foo(R (*fptr)(A))
{
puts(__PRETTY_FUNCTION__);
}
int main()
{
foo( [](double x) { return int(x); } ); // error
foo( +[](double x) { return int(x); } ); // compiles
}
-
void ContainingClass::SomeMethod()
{
class AnonymousClass$0
{
public:
AnonymousClass$0() { }
operator int (__cdecl *)(int k) { return cdecl_static_function; }
operator int (__stdcall *)(int k) { return stdcall_static_function; }
operator int (__fastcall *)(int k) { return fastcall_static_function; }
int operator(int k) { return cdecl_static_function(k); }
private:
static int __cdecl cdecl_static_function(int k) { return calc(k + 42); }
static int __stdcall stdcall_static_function(int k) { return calc(k + 42); }
static int __fastcall fastcall_static_function(int k) { return calc(k + 42); }
};
auto f = AnonymousClass$0();
...
}
-Partial specialization(Variable template):
Ref: variable_template
variable template can be defined in namespace level or class level;
it self is simply a class template with static data member; the static data member is the variable template's variable.
N4606: “Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program outside of a discarded statement.”
---
ODR-use Informally
an object is odr-used if
---
N4606: “An inline function or variable shall be defined in every translation unit in which it is odr-used outside of a discarded statement.”
Inline variable:
ref:
http://en.cppreference.com/w/cpp/language/inline
N4606: “A function template, member function of a class template, variable template, or static data member of a class template shall be defined in every translation unit in which it is implicitly instantiated, unless the corresponding specialization is explicitly instantiated in some translation unit.”
--
“Discarded statement” is C++17ese for “untaken branch of an if-constexpr”.
Ref:
http://en.cppreference.com/w/cpp/language/if
--
Constexpr If The statement that begins with if constexpr is known as the constexpr if statement.
In a constexpr if statement, the value of condition must be a contextually converted constant expression of type bool.
If the value is true, then statement-false is discarded (if present), otherwise, statement-true is discarded.
The return statements in a discarded statement do not participate in function return type deduction, and if a constexpr if statement appears inside a templated entity, and if condition is not value-dependent after instantiation, the discarded statement is not instantiated when the enclosing template is instantiated
(in particular, it can odr-use a variable that is not defined).
Difference behavior between compilers:
-
C++17:
inline variables:
--- template<auto> -
--
Template parameter deduction for class template constructors:
-
---
User-defined deduction guides:
ref: http://en.cppreference.com/w/cpp/language/class_template_deduction
-
explicit(optional) template-name ( parameter-declaration-clause ) -> simple-template-id ;
-
Explicit deduction guides for class template constructors
Ref:
Class template deduction(since C++17)
template<typename T>
constexpr bool is_array = false;
template<typename Tp>
constexpr bool is_array<Tp[]> = true;
template<typename Tp, int N>
constexpr bool is_array<Tp[N]> = true;
template<> // this is a full specialization
constexpr bool is_array<void> = true;
-N4606: “Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program outside of a discarded statement.”
---
ODR-used (重要)
https://en.cppreference.com/w/cpp/language/definition#ODR-useODR-use Informally
an object is odr-used if
- its value is read (unless it is a compile time constant)
- or written,
- its address is taken,
- or a reference is bound to it;
- it is used and
- its referent is not known at compile time;
- a function call to it is made
- or its address is taken.
- its definition must exist somewhere in the program;
---
N4606: “An inline function or variable shall be defined in every translation unit in which it is odr-used outside of a discarded statement.”
Inline variable:
ref:
http://en.cppreference.com/w/cpp/language/inline
N4606: “A function template, member function of a class template, variable template, or static data member of a class template shall be defined in every translation unit in which it is implicitly instantiated, unless the corresponding specialization is explicitly instantiated in some translation unit.”
--
“Discarded statement” is C++17ese for “untaken branch of an if-constexpr”.
Ref:
http://en.cppreference.com/w/cpp/language/if
--
Constexpr If The statement that begins with if constexpr is known as the constexpr if statement.
In a constexpr if statement, the value of condition must be a contextually converted constant expression of type bool.
If the value is true, then statement-false is discarded (if present), otherwise, statement-true is discarded.
The return statements in a discarded statement do not participate in function return type deduction, and if a constexpr if statement appears inside a templated entity, and if condition is not value-dependent after instantiation, the discarded statement is not instantiated when the enclosing template is instantiated
(in particular, it can odr-use a variable that is not defined).
Difference behavior between compilers:
-
template <typename T> T vt;
// GCC: this is a definition just as much as "int v;" would be
// Clang: this is just a declaration, akin to "extern int v;"
int i = vt<int>;
// GCC/MSVC reserve space for vt<int> here;
// Clang merely sets you up for a linker error
template<class T, class... Us, class V> void f();
f<int,char,int>(); // T=int; Us=<char,int>; V cannot be deduced
template<class... Ts, class U> void g(U);
g<int,char>(3.1); // Ts=<int,char>; U=double
template<class... Ts> void h(Ts...);
h<int,char>(0, 0, 3.1); // Ts=<int,char,double>
template<class... Ts, class U> void f(U, Ts...);
f('x', 1, 2); // U=char; Ts=<int,int>
template<class T, class... Us> void g(Us... us, T);
g('x', 1, 2); // us doesn’t contribute to deduction, so this fails
template<class T, class... Us> void h(Us... us, T);
h<int,int,int>('x', 1, 2); // us doesn’t contribute to deduction,
// but we explicitly stated T=int, Us=<int,int>, which happens to work!
-----------C++17:
inline variables:
--- template<auto> -
template<class Ty, Ty Value>
struct integral_constant {
static constexpr auto value = Value;
};
template<auto Value>
struct new_integral_constant {
static constexpr auto value = Value;
};
--
Template parameter deduction for class template constructors:
-
template<typename T>
struct myvec {
explicit myvec(T t); // constructor
};
int main() {
myvec v(1);
}
template<typename T>
struct myvec {
myvec(T t); //choose
myvec(T *p);
};
int main() {
myvec v(1);
}
--
template<typename T>
struct myvec {
myvec(T t);
myvec(T *p); //choose
};
int main() {
int i;
myvec v(&i);
// OK in C++17
}
-
template<typename T>
struct myvec {
myvec(T t); // choose, since only by choosing this could the type T be deduced.
myvec(double d);
};
int main() {
myvec v(1.0); // OK in C++17
}
-
template<typename T>
struct myvec {
myvec(T t); // Choose, T = int*, int* matches below T*
};
template<typename T>
struct myvec<T*> {
myvec(T* t); // Match here!!!
};
int main() {
int i;
myvec v(&i); // OK in C++17, however, we have partial specialized myvec here...
}
---
User-defined deduction guides:
ref: http://en.cppreference.com/w/cpp/language/class_template_deduction
-
explicit(optional) template-name ( parameter-declaration-clause ) -> simple-template-id ;
-
template<typename T>
struct myvec {
myvec(T t);
myvec(double d);
};
myvec(double) -> myvec<int>;
int main() {
myvec v(1.0);
}
-
// declaration of the template
template<class T> struct container {
container(T t) {}
template<class Iter> container(Iter beg, Iter end);
};
// additional deduction guide
template<class Iter>
container(Iter b, Iter e) -> container<typename std::iterator_traits<Iter>::value_type>;
// uses
container c(7); // OK: deduces T=int using an automatic guide
std::vector<double> v = { /* ... */};
auto d = container(v.begin(), v.end()); // OK: deduces T=double
container e{5, 6}; // Error: there is no std::iterator_traits<int>::value_type
--Explicit deduction guides for class template constructors
Ref:
Class template deduction(since C++17)
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.