I was reading book "template compelte guide" , I section : 12.2.1 Signatures I couldn't understand a sentence of author :
Its return type, if the function is generated from a function template
what does the author means by "function generated by function template" ? , is he talking about template-id here? if so, why does return type matters in the case, since signature is defined by us?
A trivial example will be helpful, thanks.
In section 12.2.1 the authors describe under which situations declarations of functions can coexist. The declaration of function templates can coexist even if they have a different return type, e.g., you can declare:
template <typename T> int f();
tepmlate <typename T> char f();
If you make these functions non-templates, you can't even declare them. Of course, in the form above you won't be able to call the function although you may be able to explicitly the select one of the functions using a cast (I'm not sure about this).
The primary use of having functions with different return types coexist (although this wasn't the original intent), is to remove some of these functions from the overload set based on condition, e.g.:
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_specialized, T>::type
f(T); // used for types for which std::numeric_limits<T> is specialied
template <typename T>
typename std::enable_if<!std::numeric_limits<T>::is_specialized, T>::type
f(T); // used for types for which std::numeric_limits<T> is not specialied
Related
I'm trying to write a C++20 concept to express the requirement that a type have a certain method, which takes an argument, but for the purposes of this concept I don't care what the argument type is.
I've tried to write something like:
template <typename T>
concept HasFooMethod = requires(T t, auto x)
{
{ t.Foo(x) } -> std::same_as<void>;
};
however, both gcc and clang reject this, giving an error that 'auto' cannot be used in the parameter list of a requires expression this way.
An alternative would be to put the type of 'x' as a second template parameter:
template <typename T, typename TX>
concept HasFooMethod = requires(T t, TX x)
{
{ t.Foo(x) } -> std::same_as<void>;
};
but then this requires TX to be specified explicitly whenever the concept is used, it cannot be deduced:
struct S { void Foo(int); };
static_assert(HasFooMethod<S>); // doesn't compile
static_assert(HasFooMethod<S, int>); // the 'int' must be specified
Is there any way to write a concept that allows Foo to take an argument of unspecified type?
The question Concept definition requiring a constrained template member function is very similar, but not the same: that question asks how to require that a (templated) method can take any type satisfying a given concept, while this question is about requiring that a method takes some particular type, although that type is unspecified. In terms of quantifiers, the other question is asking about (bounded) universal quantification while this one is about existential quantification. The other question's answer also does not apply to my case.
Concepts are not intended to provide the kind of functionality you are looking for. So they don't provide it.
A concept is meant to constrain templates, to specify a set of expressions or statements that a template intends to use (or at least be free to use) in its definition.
Within the template that you are so constraining, if you write the expression t.Foo(x), then you know the type of x. It is either a concrete type, a template parameter, or a name derived from a template parameter. Either way, the type of x is available at the template being constrained.
So if you want to constrain such a template, you use both the type of t and the type of x. Both are available to you at that time, so there is no problem with creating such a constraint. That is, the constraint is not on T as an isolated type; it's on the association between T and X.
Concepts aren't meant to work in a vacuum, devoid of any association with the actual place of usage of the constraint. You shouldn't focus on creating unary concepts so that users can static_assert their classes against them. Concepts aren't meant for testing if a type fulfills them (which is basically what your static_assert is doing); they're meant for constraining the template definition that uses them.
Your constraint needs to be FooCallableWith, not HasFooMethod.
Something close to this can be accomplished by defining an adapter type that can implicitly convert to (almost) anything:
struct anything
{
// having both these conversions allows Foo's argument to be either
// a value, an lvalue reference, or an rvalue reference
template <typename T>
operator T&();
template <typename T>
operator T&&();
};
Note that these operators do not need to be implemented, as they will only be used in an unevaluated context (and indeed, they could not be implemented for all types T).
Then, HasFooMethod can be written as:
template <typename T>
concept HasFooMethod = requires(T t, anything a)
{
{ t.Foo(a) } -> std::same_as<void>;
};
I am want a static check of the parameter type of lambdas. I've written this code below and it seems to produce the correct result.
struct B { };
auto lamBc = [](B const& b) { std::cout << "lambda B const" << std::endl; };
template<typename ClosureType, typename R, typename Arg>
constexpr auto ArgType(R (ClosureType::*)(Arg) const)->Arg;
template <typename T>
using ArgType_t = decltype(ArgType(&T::operator()));
// ArgType_t<lamBc> is "reference to B const"
However, I noticed that, for example, the standard library uses class template specialization to extract the referred-to type from a reference type in std::remove_reference. So I tried that approach and it also seems to produce the correct result.
template<typename L>
struct ArgType2;
template<typename ClosureType, typename R, typename Arg>
struct ArgType2<R (ClosureType::*)(Arg) const>
{
typedef Arg type;
};
template <typename T>
using ArgType2_t = typename ArgType2<decltype(&T::operator())>::type;
// ArgType2_t<lamBc> is also "reference to B const"
My questions are: Which is the standard way to extract types from a pattern expression? What are the trade-offs in either approach?
Both your approaches are valid, interchangeable and lead to the same result (deduce the type of the parameter lambda accepts).
For type traits it is required by the standard (see 23.15.1 Requirements) that:
A UnaryTypeTrait describes a property of a type. It shall be a class template that takes one template type argument and, optionally, additional arguments that help define the property being described. ...
A BinaryTypeTrait describes a relationship between two types. It shall be a class template that takes two template type arguments
and, optionally, additional arguments that help define the
relationship being described. ...
A TransformationTrait modifies a property of a type. It shall be a class template that takes one template type argument and, optionally, additional arguments that help define the modification. ...
I suppose that this requirement appeared mostly for historical reasons as decltype functionality was introduced after type traits had been proposed (and these type traits were based on type traits from boost which had been created even earlier, see, for example, this).
Also, note, that class templates are more flexible for general purpose type traits than the logic based on functions declarations and decltype.
The main point is that with C++11 and later in your particular case you are free to use the way which is the most convenient and reflects the programming logic better.
They are both "standard", the decltype() way is simply available in modern C++ variants, the PTS method was the only way to do this sort of things under the original C++ standard.
I was learning some C++ idioms when I came across a sample code for SFINAE, I was perplexed with the code.
Note: is_ptr() has no definition.
I compiled the code myself, no compiler errors regarding lack of function definition, why?
sizeof() was used on one of the calls, it apparently executed on the returns of the functions, but then again, there was no definition. How was that possible?
template <typename T>
struct is_pointer
{
template <typename U>
static char is_ptr(U*);
template <typename X, typename Y>
static char is_ptr(X Y::*);
template <typename U>
static char is_ptr(U (*)());
static double is_ptr(...);
static T t;
enum {value = sizeof(is_ptr(t)) == sizeof(char)};
};
sizeof is what is called an un-evaluated context. Within it the expression needs to be only well formed, nothing will actually ever be executed. So a function that is only declared can be used inside without needing an actual definition.
This is because the definition is not required to determine the type information. In this case, the overload that is chosen by ADL is the type information in question. It's return type is also available from the declaration alone.
#include <type_traits>
template <typename T>
struct C;
template<typename T1, typename T2>
using first = T1;
template <typename T>
struct C<first<T, std::enable_if_t<std::is_same<T, int>::value>>>
{
};
int main ()
{
}
Results of compilation by different compilers:
MSVC:
error C2753: 'C': partial specialization cannot match argument list for primary template
gcc-4.9:
error: partial specialization 'C' does not specialize any template arguments
clang all versions:
error: class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list
gcc-5+:
successfully compiles
And additionaly I want to point out that trivial specialization like:
template<typename T>
struct C<T>
{
};
successfully fails to be compiled by gcc. So it seems like it figures out that specialization in my original example is non-trivial. So my question is - is pattern like this explicitly forbidden by C++ standard or not?
The crucial paragraph is [temp.class.spec]/(8.2), which requires the partial specialization to be more specialized than the primary template. What Clang actually complains about is the argument list being identical to the primary template's: this has been removed from [temp.class.spec]/(8.3) by issue 2033 (which stated that the requirement was redundant) fairly recently, so hasn't been implemented in Clang yet. However, it apparently has been implemented in GCC, given that it accepts your snippet; it even compiles the following, perhaps for the same reason it compiles your code (it also only works from version 5 onwards):
template <typename T>
void f( C<T> ) {}
template <typename T>
void f( C<first<T, std::enable_if_t<std::is_same<T, int>::value>>> ) {}
I.e. it acknowledges that the declarations are distinct, so must have implemented some resolution of issue 1980. It does not find that the second overload is more specialized (see the Wandbox link), however, which is inconsistent, because it should've diagnosed your code according to the aforementioned constraint in (8.2).
Arguably, the current wording makes your example's partial ordering work as desired†: [temp.deduct.type]/1 mentions that in deduction from types,
Template arguments can be deduced in several different contexts, but in each case a type that is specified in terms of template parameters (call it P) is compared with an actual type (call it A), and an attempt is made to find template argument values […] that will make P, after substitution of the deduced values (call it the deduced A), compatible with A.
Now via [temp.alias]/3, this would mean that during the partial ordering step in which the partial specialization's function template is the parameter template, the substitution into is_same yields false (since common library implementations just use a partial specialization that must fail), and enable_if fails.‡ But this semantics is not satisfying in the general case, because we could construct a condition that generally succeeds, so a unique synthesized type meets it, and deduction succeeds both ways.
Presumably, the simplest and most robust solution is to ignore discarded arguments during partial ordering (making your example ill-formed). One can also orientate oneself towards implementations' behaviors in this case (analogous to issue 1157):
template <typename...> struct C {};
template <typename T>
void f( C<T, int> ) = delete;
template <typename T>
void f( C<T, std::enable_if_t<sizeof(T) == sizeof(int), int>> ) {}
int main() {f<int>({});}
Both Clang and GCC diagnose this as calling the deleted function, i.e. agree that the first overload is more specialized than the other. The critical property of #2 seems to be that the second template argument is dependent yet T appears solely in non-deduced contexts (if we change int to T in #1, nothing changes). So we could use the existence of discarded (and dependent?) template arguments as tie-breakers: this way we don't have to reason about the nature of synthesized values, which is the status quo, and also get reasonable behavior in your case, which would be well-formed.
† #T.C. mentioned that the templates generated through [temp.class.order] would currently be interpreted as one multiply declared entity—again, see issue 1980. That's not directly relevant to the standardese in this case, because the wording never mentions that these function templates are declared, let alone in the same program; it just specifies them and then falls back to the procedure for function templates.
‡ It isn't entirely clear with what depth implementations are required to perform this analysis. Issue 1157 demonstrates what level of detail is required to "correctly" determine whether a template's domain is a proper subset of the other's. It's neither practical nor reasonable to implement partial ordering to be this sophisticated. However, the footnoted section just goes to show that this topic isn't necessarily underspecified, but defective.
I think you could simplify your code - this has nothing to do with type_traits. You'll get the same results with following one:
template <typename T>
struct C;
template<typename T>
using first = T;
template <typename T>
struct C<first<T>> // OK only in 5.1
{
};
int main ()
{
}
Check in online compiler (compiles under 5.1 but not with 5.2 or 4.9 so it's probably a bug) - https://godbolt.org/g/iVCbdm
I think that int GCC 5 they moved around template functionality and it's even possible to create two specializations of the same type. It will compile until you try to use it.
template <typename T>
struct C;
template<typename T1, typename T2>
using first = T1;
template<typename T1, typename T2>
using second = T2;
template <typename T>
struct C<first<T, T>> // OK on 5.1+
{
};
template <typename T>
struct C<second<T, T>> // OK on 5.1+
{
};
int main ()
{
C<first<int, int>> dummy; // error: ambiguous template instantiation for 'struct C<int>'
}
https://godbolt.org/g/6oNGDP
It might be somehow related to added support for C++14 variable templates. https://isocpp.org/files/papers/N3651.pdf
For example:
template <typename T>
struct foo
{
using bar = int;
};
// _Z3bazi
void baz(foo<int>::bar quux) {
}
template <typename T>
void baz(typename foo<T>::bar quux) {
}
// _Z3bazIiEvN3fooIT_E3barE
template void baz<int>(foo<int>::bar quux);
Why does the mangled form of baz<int> mention foo at all? How come it's not _Z3bazIiEvi?
This is apparently the reason that the C++17 std::default_order<T> proposal is dead in the water.
The issue comes from the <unresolved-name> construct in the ABI. Why would we ever want to use an unresolved name? It's all about declaration matching and overloads. C++14 §14.5.6.1/3 notes,
Two distinct function templates may have identical function return types and function parameter lists, even if overload resolution alone cannot distinguish them.
You can have another function in a different file,
template <typename T>
void baz(int quux) { std::abort(); }
Although this signature can't peacefully coexist in the same file — it cannot be named because of overload ambiguity — it can exist in a different file so it needs a distinct mangling.
(Even this level of coexistence is not guaranteed by the standard for all templates. It's a matter of QOI that the compiler uses the exact form of a function template declaration to perform declaration matching, so that copy-pasting a declaration into a definition will tend to provide an exact match and not a surprising conflict with another function template that resolves to the same signature. See §14.5.6.1/5-6.)
As for raining on default_order's parade, the problem is that template-ids implicitly pull default arguments from templates. So the user could unintentionally have a dependent typename in a signature just by mentioning std::set.