You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
sort(v, greater); // pointer to function: potentially slow
13557
+
sort(v, greater); // pointer to function: potentially slow
13546
13558
sort(v, [](double x, double y) { return x > y; }); // function object
13547
-
sort(v, greater<>); // function object
13559
+
sort(v, std::greater<>); // function object
13548
13560
13549
13561
bool greater_than_7(double x) { return x > 7; }
13550
-
auto x = find_if(v, greater_than_7); // pointer to function: inflexible
13562
+
auto x = find_if(v, greater_than_7); // pointer to function: inflexible
13551
13563
auto y = find_if(v, [](double x) { return x > 7; }); // function object: carries the needed data
13552
-
auto z = find_if(v, Greater_than<double>(7)); // function object: carries the needed data
13564
+
auto z = find_if(v, Greater_than<double>(7)); // function object: carries the needed data
13553
13565
13554
13566
You can, of course, generalize those functions using `auto` or (when and where available) concepts. For example:
13555
13567
@@ -13812,8 +13824,8 @@ Because that's the best we can do without direct concept support.
13812
13824
13813
13825
##### Note
13814
13826
13815
-
Beware of [negating constraints](# T.25).
13816
-
Faking concept overloading using `enable_if` sometimes forces us to use that error-prone designs.
13827
+
Beware of [complementary constraints](# T.25).
13828
+
Faking concept overloading using `enable_if` sometimes forces us to use that error-prone design technique.
13817
13829
13818
13830
##### Enforcement
13819
13831
@@ -13861,11 +13873,24 @@ Eases tool creation.
13861
13873
std::sort(begin(c),end(c)); // necessary and useful dependency
13862
13874
}
13863
13875
13864
-
??? // potentially surprising dependency
13876
+
template<typename Iter>
13877
+
Iter algo(Iter first, Iter last) {
13878
+
for (; first!=last; ++first) {
13879
+
auto x = sqrt(*first); // potentially surprising dependency: which sqrt()?
13880
+
helper(first,x); // potentially surprising dependency: heper is chosen based on first and x
13881
+
TT var = 7; // potentially surprising dependency: which TT?
13882
+
}
13883
+
}
13865
13884
13866
13885
##### Note
13867
13886
13868
-
Having a template operate only on its arguments would be one way of reducing the number of dependencies to a minimum, but that would generally be unmanageable. For example, an algorithm usually uses other algorithms.
13887
+
Templates typically appear in header files so their context dependencies are more vulnerable to `#include` order dependencies than functions in `.cpp` files.
13888
+
13889
+
##### Note
13890
+
13891
+
Having a template operate only on its arguments would be one way of reducing the number of dependencies to a minimum, but that would generally be unmanageable.
13892
+
For example, an algorithm usually uses other algorithms and invoke operations that does not exclusively operate on arguments.
13893
+
And don't get us started on macros!
13869
13894
See also [T69](#???)
13870
13895
13871
13896
##### Enforcement
@@ -13938,11 +13963,11 @@ This looks innocent enough, but ???
13938
13963
* Flag member types that do not depend on every template argument
13939
13964
* Flag member functions that do not depend on every template argument
13940
13965
13941
-
### <a name="Rt-nondependent"></a>T.62: Place non-dependent template members in a non-templated base class
13966
+
### <a name="Rt-nondependent"></a>T.62: Place non-dependent class template members in a non-templated base class
13942
13967
13943
13968
##### Reason
13944
13969
13945
-
???
13970
+
Allow the base class members to be used without specifying template arguments and without template instantiation.
13946
13971
13947
13972
##### Example
13948
13973
@@ -14003,15 +14028,63 @@ Specialization offers a powerful mechanism for providing alternative implementat
14003
14028
14004
14029
##### Reason
14005
14030
14006
-
A template defines a general interface. ???
14031
+
A template defines a general interface.
14032
+
Tag dispatch allows us to select implmentations based on specific properties of an argument type.
14033
+
Performance.
14007
14034
14008
14035
##### Example
14009
14036
14010
-
??? that's how we get algorithms like `std::copy` which compiles into a `memmove` call if appropriate for the arguments.
14037
+
This is a simplified version of `std::copy` (ignoring the possibility of non-contiguous sequences)
14038
+
14039
+
struct pod_tag {};
14040
+
struct non_pod_tag;
14041
+
14042
+
template<class T> struct copy_trait { using tag = non_pod_tag; }; // T is not "plain old data"
14043
+
14044
+
template<> struct copy_trait<int> { using tab = pod_tag; }; // int is "plain old data"
14045
+
14046
+
template<class Iter>
14047
+
Out copy_helper(Iter first, Iter last, Iter out, pog_tag)
14048
+
{
14049
+
// use memmove
14050
+
}
14051
+
14052
+
template<class Iter>
14053
+
Out copy_helper(Iter first, Iter last, Iter out, non_pod_tag)
copy(vs.begin(),vs.end(), vs2.begin()); // uses a loop calling copy constructors
14068
+
}
14069
+
14070
+
This is a general and powerful technique for compile-time algorithm selection.
14011
14071
14012
14072
##### Note
14013
14073
14014
-
When `concept`s become available such alternatives can be distinguished directly.
14074
+
When `concept`s become widely available such alternatives can be distinguished directly:
14075
+
14076
+
template<class Iter>
14077
+
requires Pod<Value_type_iter>
14078
+
Out copy_helper(In, first, In last, Out out)
14079
+
{
14080
+
// use memmove
14081
+
}
14082
+
14083
+
template<class Iter>
14084
+
Out copy_helper(In, first, In last, Out out)
14085
+
{
14086
+
// use loop calling copy constructors
14087
+
}
14015
14088
14016
14089
##### Enforcement
14017
14090
@@ -14036,57 +14109,76 @@ When `concept`s become available such alternatives can be distinguished directly
14036
14109
14037
14110
##### Reason
14038
14111
14039
-
???
14112
+
`()` is vulnerable to grammar ambiguities.
14040
14113
14041
14114
##### Example
14042
14115
14043
-
???
14116
+
template<typename T, typename U>
14117
+
void f(T t, U u)
14118
+
{
14119
+
T v1(x); // is v1 a function of a variable?
14120
+
T v2 {x}; // variable
14121
+
auto x = T(u); // construction or cast?
14122
+
}
14123
+
14124
+
f(1,"asdf); // bad: cast from const char* to int
14044
14125
14045
14126
##### Enforcement
14046
14127
14047
-
???
14128
+
* flag `()` initializers
14129
+
* flag function-style casts
14130
+
14048
14131
14049
14132
### <a name="Rt-customization"></a>T.69: Inside a template, don't make an unqualified nonmember function call unless you intend it to be a customization point
14050
14133
14051
14134
##### Reason
14052
14135
14053
-
To provide only intended flexibility, and avoid accidental environmental changes.
14136
+
Provide only intended flexibility.
14137
+
Avoid vulnarability to accidental environmental changes.
14054
14138
14055
-
If you intend to call your own helper function `helper(t)` with a value `t` that depends on a template type parameter, put it in a `::detail` namespace and qualify the call as `detail::helper(t);`. Otherwise the call becomes a customization point where any function `helper` in the namespace of `t`'s type can be invoked instead -- falling into the second option below, and resulting in problems like [unintentionally invoking unconstrained function templates of that name that happen to be in the same namespace as `t`'s type](#Rt-unconstrained-adl).
14139
+
##### Example
14056
14140
14057
14141
There are three major ways to let calling code customize a template.
14058
14142
14059
-
* Call a member function. Callers can provide any type with such a named member function.
14060
-
14061
14143
template<class T>
14062
-
void test(T t)
14144
+
// Call a member function
14145
+
void test1(T t)
14063
14146
{
14064
14147
t.f(); // require T to provide f()
14065
14148
}
14066
14149
14067
-
* Call a nonmember function without qualification. Callers can provide any type for which there is such a function available in the caller's context or in the namespace of the type.
14068
-
14069
14150
template<class T>
14070
-
void test(T t)
14151
+
void test2(T t)
14152
+
// Call a nonmember function without qualification
14071
14153
{
14072
-
// require f(/*T*/) be available in caller's scope or in T's namespace
14073
-
f(t);
14154
+
f(t); // require f(/*T*/) be available in caller's scope or in T's namespace
14074
14155
}
14075
14156
14076
-
* Invoke a "trait" -- usually a type alias to compute a type, or a `constexpr` function to compute a value, or in rarer cases a traditional traits template to be specialized on the user's type.
14077
-
14078
14157
template<class T>
14079
-
void test(T t)
14080
-
{
14081
-
// require customizing test_traits<> to get non-default functions/types
14082
-
test_traits<T>::f(t);
14083
-
test_traits<T>::value_type x;
14158
+
void test3(T t)
14159
+
// Invoke a "trait"
14160
+
14161
+
{
14162
+
test_traits<T>::f(t); // require customizing test_traits<> to get non-default functions/types
14084
14163
}
14085
14164
14165
+
A trait is usually a type alias to compute a type,
14166
+
a `constexpr` function to compute a value,
14167
+
or a traditional traits template to be specialized on the user's type.
14168
+
14169
+
##### Note
14170
+
14171
+
If you intend to call your own helper function `helper(t)` with a value `t` that depends on a template type parameter,
14172
+
put it in a `::detail` namespace and qualify the call as `detail::helper(t);`.
14173
+
An unqualified call becomes a customization point where any function `helper` in the namespace of `t`'s type can be invoked;
14174
+
this can cause problems like [unintentionally invoking unconstrained function templates](#Rt-unconstrained-adl).
14175
+
14176
+
14086
14177
##### Enforcement
14087
14178
14088
14179
* In a template, flag an unqualified call to a nonmember function that passes a variable of dependent type when there is a nonmember function of the same name in the template's namespace.
14089
14180
14181
+
14090
14182
## <a name="SS-temp-hier"></a>T.temp-hier: Template and hierarchy rules:
14091
14183
14092
14184
Templates are the backbone of C++'s support for generic programming and class hierarchies the backbone of its support
@@ -14162,7 +14254,7 @@ Never write such code.
14162
14254
14163
14255
Note that `maul()` violates the a `T*` points to an individual object [Rule](#???).
14164
14256
14165
-
**Alternative**: Use a proper container:
14257
+
**Alternative**: Use a proper (templatized) container:
0 commit comments