template <class T, class U> decltype(*(T*)(0) * *(U*)(0)) mul(T x, U y) {
return x * y;
}
This piece of code was taken from Stroustrup's C++11 FAQ. I understand what it does, which is multiply two objects of varying types. What perplexes me is the syntax between the template parameters and the function definition. What is happening inside decltype? I take it that it's dereferencing an unnammed T pointer initialized to 0, and multiplying it by an unnamed U pointer being dereferenced and initialized in the same way. Am I right?
Well, if this is what is happening, then isn't the use of pointers, dereferences, and extra parenthesis superfluous? Couldn't I initialize the types like this while maintaining the desired effect?:
template <class T, class U> decltype(T(0) * U(0)) mul(T x, U y) {
return x * y;
}
This looks much cleaner to me, and it does have the same effect when multiplying two numbers like in the first...
mul(4, 3); // 12
So why does Stroustrup insist on using complex pointer, dereference and initialization syntax? This is, of course, before he introduced the new auto syntax. But anyway, my question is: Is there any difference between the two above forms of type initialization? Where he uses pointers and instantly dereferences them instead of simply doing what I did, which was to initialize the types with no pointers or dereferencing? Any response is appreciated.
Your version is not equivalent.
Your version supposes that both T and U can be constructed from 0. It's obviously wrong to expect this from matrices, yet they can be multiplied.
T(0) yields a temporary (that may bind to T&&) whilst *(T*(0)) yields a reference to an existing object (that is, T&), therefore a different operator might be selected.
However, neither Stroustrup's version nor yours end up being used in practice. At an equivalent level of compiler implementation, one would use:
template <typename T, typename U>
decltype(std::declval<T>() * std::declval<U>()) mul(T x, U y);
But it's failing to take advantage of Late Return Type specification, built to allow postponing the declaration of the return type after the function's arguments declaration: auto f(int, int) -> int. Once the arguments have been declared, they can be used, which is incredibly useful for decltype!
template <typename T, typename U>
auto mul(T x, U y) -> decltype(x * y);
This latter form is guaranteed to pick the same operator overload than the function body, at the cost of repetition (unfortunately).
Your version of the code supposes that T and U have default constructors. Stroustrup version doesn't, it creates a dummy object by dereferencing a null pointer. That doesn't matter of course because that code is not meant to be executed, it's only meant to be parsed to know the resulting type.
decltype content is unevaluated context; it doesn't matter what is there, as long as it results with a type. Think for a second about T being defined like this:
struct T
{
int operator*(const U &) { return 2; }
};
It doesn't have constructor taking int or any type that int is convertible to; therefore, T(0) does not result in an object, even in unevaluated context of decltype. Therefore, using unevaluated null references is possibly the easiest way to get proper type.
Bottom line: you don't know what constructors do T and U have, so you should use null reference that references dummy object of proper type.
Related
Is there any reason that c++ compiler gives error when using two different numeric variable types in std::max() function? (e.g. int and long).
I mean something like: "Sometimes we have this problem when using std::max() function for two different numeric variable types, so the compiler gives error to prevent this problem".
The compiler produces an error because it cannot perform type deduction for the template argument of std::max. This is how std::max template is declared: the same type (template parameter) is used for both arguments. If the arguments have different types, the deduction becomes ambiguous.
If you work around the deduction ambiguity by supplying the template argument explicitly, you will be able to use different types as std::max arguments
std::max(1, 2.0); // Error
std::max<double>(1, 2.0); // OK
The reason why std::max insists on using a common type for its arguments (instead of using two independent types) is described in #bolov's answer: the function actually wants to return a reference to the maximum value.
std::max returns a reference to the argument that has the maximum value. The main reason it is this way is because it is a generic function and as such it can be used with types expensive to copy. Also you might actually need just a reference to the object, instead a copy of it.
And because it returns a reference to a argument, all arguments must be of the same type.
The direct answer to the question is that it's because std::min and std::max take only one template parameter that defines the types of both arguments. If/when you try to pass arguments of different types, the compiler can't decide which of those two types to use for the template argument, so the code is ambiguous. As originally defined in C++98, std::min and std::max had signatures like these (C++03, §[lib.alg.min.max]):
template<class T> const T& min(const T& a, const T& b);
template<class T, class Compare>
const T& min(const T& a, const T& b, Compare comp);
template<class T> const T& max(const T& a, const T& b);
template<class T, class Compare>
const T& max(const T& a, const T& b, Compare comp);
So the basic idea here is that the function receives two objects by reference, and returns a reference to one of those objects. If it received objects of two different types, it wouldn't be able to return a reference to an input object because one of the objects would necessarily be of a different type than it was returning (so #bolov is correct about that part, but I don't think it's really the whole story).
With a modern compiler/standard library, if you don't might dealing with values instead of references, you could pretty easily write code on this general order:
template <class T, class U>
std::common_type<T, U> min(T const &a, U const &b) {
return b < a ? b : a;
}
template <class T, class U>
std::common_type<T, U> max(T const &a, U const &b) {
return a < b ? b : a;
}
That makes it pretty easy to deal with your case of passing an int and a long (or other pairs of types, as long as std::common_type can deduce some common type for them, and a<b is defined for objects of the two types.
But, in 1998, even if std::common_type had been available so it was easy to do, that solution probably wouldn't have been accepted (and as we'll see, it's still open to some question whether it's a great idea)--at the time, many people still thought in terms of lots of inheritance, so it was (more or less) taken for granted that you'd frequently use it in situations where both arguments were really of some derived type, something on this general order:
class Base {
// ...
virtual bool operator<(Base const &other);
};
class Derived1 : public Base {
// ...
};
class Derived2 : public Base {
// ...
};
Derived1 d1;
Derived2 d2;
Base &b = std::max(d1, d2);
In this case, the version above that returns a value instead of returning a reference would cause a serious problem. common_type<Derived1, Derived2> is going to be Base, so we'd end up slicing the argument to create an object of type Base, and returning that. This would rarely provide desirable behavior (and in some cases, such as if Base were an abstract base class, it wouldn't even compile).
There's one other point that's probably worth noting: even when applied in a seemingly simple situation, std::common_type can produce results you might not expect. For example, let's consider calling the template defined above like:
auto x = min(-1, 1u);
That leaves us with an obvious question: what type will x be?
Even though we've passed it an int and an unsigned, the type of the result is (at least potentially) neither int or unsigned (e.g., quite possibly long long)!
Is there any reason that c++ compiler gives error when using two different numeric variable types in std::max() function? (e.g. int and long).
I mean something like: "Sometimes we have this problem when using std::max() function for two different numeric variable types, so the compiler gives error to prevent this problem".
The compiler produces an error because it cannot perform type deduction for the template argument of std::max. This is how std::max template is declared: the same type (template parameter) is used for both arguments. If the arguments have different types, the deduction becomes ambiguous.
If you work around the deduction ambiguity by supplying the template argument explicitly, you will be able to use different types as std::max arguments
std::max(1, 2.0); // Error
std::max<double>(1, 2.0); // OK
The reason why std::max insists on using a common type for its arguments (instead of using two independent types) is described in #bolov's answer: the function actually wants to return a reference to the maximum value.
std::max returns a reference to the argument that has the maximum value. The main reason it is this way is because it is a generic function and as such it can be used with types expensive to copy. Also you might actually need just a reference to the object, instead a copy of it.
And because it returns a reference to a argument, all arguments must be of the same type.
The direct answer to the question is that it's because std::min and std::max take only one template parameter that defines the types of both arguments. If/when you try to pass arguments of different types, the compiler can't decide which of those two types to use for the template argument, so the code is ambiguous. As originally defined in C++98, std::min and std::max had signatures like these (C++03, §[lib.alg.min.max]):
template<class T> const T& min(const T& a, const T& b);
template<class T, class Compare>
const T& min(const T& a, const T& b, Compare comp);
template<class T> const T& max(const T& a, const T& b);
template<class T, class Compare>
const T& max(const T& a, const T& b, Compare comp);
So the basic idea here is that the function receives two objects by reference, and returns a reference to one of those objects. If it received objects of two different types, it wouldn't be able to return a reference to an input object because one of the objects would necessarily be of a different type than it was returning (so #bolov is correct about that part, but I don't think it's really the whole story).
With a modern compiler/standard library, if you don't might dealing with values instead of references, you could pretty easily write code on this general order:
template <class T, class U>
std::common_type<T, U> min(T const &a, U const &b) {
return b < a ? b : a;
}
template <class T, class U>
std::common_type<T, U> max(T const &a, U const &b) {
return a < b ? b : a;
}
That makes it pretty easy to deal with your case of passing an int and a long (or other pairs of types, as long as std::common_type can deduce some common type for them, and a<b is defined for objects of the two types.
But, in 1998, even if std::common_type had been available so it was easy to do, that solution probably wouldn't have been accepted (and as we'll see, it's still open to some question whether it's a great idea)--at the time, many people still thought in terms of lots of inheritance, so it was (more or less) taken for granted that you'd frequently use it in situations where both arguments were really of some derived type, something on this general order:
class Base {
// ...
virtual bool operator<(Base const &other);
};
class Derived1 : public Base {
// ...
};
class Derived2 : public Base {
// ...
};
Derived1 d1;
Derived2 d2;
Base &b = std::max(d1, d2);
In this case, the version above that returns a value instead of returning a reference would cause a serious problem. common_type<Derived1, Derived2> is going to be Base, so we'd end up slicing the argument to create an object of type Base, and returning that. This would rarely provide desirable behavior (and in some cases, such as if Base were an abstract base class, it wouldn't even compile).
There's one other point that's probably worth noting: even when applied in a seemingly simple situation, std::common_type can produce results you might not expect. For example, let's consider calling the template defined above like:
auto x = min(-1, 1u);
That leaves us with an obvious question: what type will x be?
Even though we've passed it an int and an unsigned, the type of the result is (at least potentially) neither int or unsigned (e.g., quite possibly long long)!
I was watching Dr. Walter E. Brown's Template Meta-programming talk. In his presentation he presents code like so for is_copy_assignable:
template<class U, class = decltype(declval<U&>() = declval<U const&>())>
static true_type try_assignment(U &&);
What I am having trouble with is how is the assignment operator being called in this instance. When I try and reason about this code and say substitute a dummy type, say int, in place of the U I get:
template<class U, class = decltype(declval<int&>() = declval<int const&>())>
template<class U, class = decltype(int& = int const&)>
So I am wondering then how can this help us determine if the assignment operator is valid. If I understand declval correctly this code will not even evaluate so then how can one determine from int& = int const&, which doesn't even evaluate, if there is or isn't a assignment operator defined for U.
I understand that in most cases the copy-assignment operator would be defined as
C& operator=(const C& other)
which looks a lot like what is above, but still since nothing is being evaluated then what use is this information.
I don't really follow what you intended in performing the following step:
template<class U, class = decltype(declval<int&>() = declval<int const&>())>
template<class U, class = decltype(int& = int const&)>
declval says: pretend to return a value of type of the template argument. I say pretend because the function isn't really defined, only declared, so it can only be used in an unevaluated context. Inside of decltype is an unevaluated contexts because you're only checking types.
So, the expression decltype(declval<int&>() = declval<int const&>()) is basically saying: if I had an int&, call it x, and I had a int const&, call it y, what is the type of the expression x = y?
As you can probably guess this calls the assignment operator and this expression will have a valid type (in this case, int&). If you change int to unique_ptr, this expression won't have a valid type, because unique_ptr is not assignable, causing type substitution to fail and eliminating this template from the overload or specialization set.
The reason to have declval at all is because it lets you create a value of any type; this is particularly useful for a) creating something of reference type, and b) creating non-reference types without assuming that they have e.g. a default constructor. Thus, use of declval is extremely ubiquitous in high quality TMP.
I'm trying to understand the implementation of std::is_class. I've copied some possible implementations and compiled them, hoping to figure out how they work. That done, I find that all the computations are done during compilation (as I should have figured out sooner, looking back), so gdb can give me no more detail on what exactly is going on.
The implementation I'm struggling to understand is this one:
template<class T, T v>
struct integral_constant{
static constexpr T value = v;
typedef T value_type;
typedef integral_constant type;
constexpr operator value_type() const noexcept {
return value;
}
};
namespace detail {
template <class T> char test(int T::*); //this line
struct two{
char c[2];
};
template <class T> two test(...); //this line
}
//Not concerned about the is_union<T> implementation right now
template <class T>
struct is_class : std::integral_constant<bool, sizeof(detail::test<T>(0))==1
&& !std::is_union<T>::value> {};
I'm having trouble with the two commented lines. This first line:
template<class T> char test(int T::*);
What does the T::* mean? Also, is this not a function declaration? It looks like one, yet this compiles without defining a function body.
The second line I want to understand is:
template<class T> two test(...);
Once again, is this not a function declaration with no body ever defined? Also what does the ellipsis mean in this context? I thought an ellipsis as a function argument required one defined argument before the ...?
I would like to understand what this code is doing. I know I can just use the already implemented functions from the standard library, but I want to understand how they work.
References:
std::is_class
std::integral_constant
What you are looking at is some programming technologie called "SFINAE" which stands for "Substitution failure is not an error". The basic idea is this:
namespace detail {
template <class T> char test(int T::*); //this line
struct two{
char c[2];
};
template <class T> two test(...); //this line
}
This namespace provides 2 overloads for test(). Both are templates, resolved at compile time. The first one takes a int T::* as argument. It is called a Member-Pointer and is a pointer to an int, but to an int thats a member of the class T. This is only a valid expression, if T is a class.
The second one is taking any number of arguments, which is valid in any case.
So how is it used?
sizeof(detail::test<T>(0))==1
Ok, we pass the function a 0 - this can be a pointer and especially a member-pointer - no information gained which overload to use from this.
So if T is a class, then we could use both the T::* and the ... overload here - and since the T::* overload is the more specific one here, it is used.
But if T is not a class, then we cant have something like T::* and the overload is ill-formed. But its a failure that happened during template-parameter substitution. And since "substitution failures are not an error" the compiler will silently ignore this overload.
Afterwards is the sizeof() applied. Noticed the different return types? So depending on T the compiler chooses the right overload and therefore the right return type, resulting in a size of either sizeof(char) or sizeof(char[2]).
And finally, since we only use the size of this function and never actually call it, we dont need an implementation.
Part of what is confusing you, which isn't explained by the other answers so far, is that the test functions are never actually called. The fact they have no definitions doesn't matter if you don't call them. As you realised, the whole thing happens at compile time, without running any code.
The expression sizeof(detail::test<T>(0)) uses the sizeof operator on a function call expression. The operand of sizeof is an unevaluated context, which means that the compiler doesn't actually execute that code (i.e. evaluate it to determine the result). It isn't necessary to call that function in order to know the sizeof what the result would be if you called it. To know the size of the result the compiler only needs to see the declarations of the various test functions (to know their return types) and then to perform overload resolution to see which one would be called, and so to find what the sizeof the result would be.
The rest of the puzzle is that the unevaluated function call detail::test<T>(0) determines whether T can be used to form a pointer-to-member type int T::*, which is only possible if T is a class type (because non-classes can't have members, and so can't have pointers to their members). If T is a class then the first test overload can be called, otherwise the second overload gets called. The second overload uses a printf-style ... parameter list, meaning it accepts anything, but is also considered a worse match than any other viable function (otherwise functions using ... would be too "greedy" and get called all the time, even if there's a more specific function t hat matches the arguments exactly). In this code the ... function is a fallback for "if nothing else matches, call this function", so if T isn't a class type the fallback is used.
It doesn't matter if the class type really has a member variable of type int, it is valid to form the type int T::* anyway for any class (you just couldn't make that pointer-to-member refer to any member if the type doesn't have an int member).
The std::is_class type trait is expressed through a compiler intrinsic (called __is_class on most popular compilers), and it cannot be implemented in "normal" C++.
Those manual C++ implementations of std::is_class can be used in educational purposes, but not in a real production code. Otherwise bad things might happen with forward-declared types (for which std::is_class should work correctly as well).
Here's an example that can be reproduced on any msvc x64 compiler.
Suppose I have written my own implementation of is_class:
namespace detail
{
template<typename T>
constexpr char test_my_bad_is_class_call(int T::*) { return {}; }
struct two { char _[2]; };
template<typename T>
constexpr two test_my_bad_is_class_call(...) { return {}; }
}
template<typename T>
struct my_bad_is_class
: std::bool_constant<sizeof(detail::test_my_bad_is_class_call<T>(nullptr)) == 1>
{
};
Let's try it:
class Test
{
};
static_assert(my_bad_is_class<Test>::value == true);
static_assert(my_bad_is_class<const Test>::value == true);
static_assert(my_bad_is_class<Test&>::value == false);
static_assert(my_bad_is_class<Test*>::value == false);
static_assert(my_bad_is_class<int>::value == false);
static_assert(my_bad_is_class<void>::value == false);
As long as the type T is fully defined by the moment my_bad_is_class is applied to it for the first time, everything will be okay. And the size of its member function pointer will remain what it should be:
// 8 is the default for such simple classes on msvc x64
static_assert(sizeof(void(Test::*)()) == 8);
However, things become quite "interesting" if we use our custom type trait with a forward-declared (and not yet defined) type:
class ProblemTest;
The following line implicitly requests the type int ProblemTest::* for a forward-declared class, definition of which cannot be seen by the compiler right now.
static_assert(my_bad_is_class<ProblemTest>::value == true);
This compiles, but, unexpectedly, breaks the size of a member function pointer.
It seems like the compiler attempts to "instantiate" (similarly to how templates are instantiated) the size of a pointer to ProblemTest's member function in the same moment that we request the type int ProblemTest::* within our my_bad_is_class implementation. And, currently, the compiler cannot know what it should be, thus it has no choice but to assume the largest possible size.
class ProblemTest // definition
{
};
// 24 BYTES INSTEAD OF 8, CARL!
static_assert(sizeof(void(ProblemTest::*)()) == 24);
The size of a member function pointer was trippled! And it cannot be shrunk back even after the definition of class ProblemTest has been seen by the compiler.
If you work with some third party libraries that rely on particular sizes of member function pointers on your compiler (e.g., the famous FastDelegate by Don Clugston), such unexpected size changes caused by some call to a type trait might be a real pain. Primarily because type trait invocations are not supposed to modify anything, yet, in this particular case, they do -- and this is extremely unexpected even for an experienced developer.
On the other hand, had we implemented our is_class using the __is_class intrinsic, everything would have been OK:
template<typename T>
struct my_good_is_class
: std::bool_constant<__is_class(T)>
{
};
class ProblemTest;
static_assert(my_good_is_class<ProblemTest>::value == true);
class ProblemTest
{
};
static_assert(sizeof(void(ProblemTest::*)()) == 8);
Invocation of my_good_is_class<ProblemTest> does not break any sizes in this case.
So, my advice is to rely on the compiler intrinsics when implementing your custom type traits like is_class wherever possible. That is, if you have a good reason to implement such type traits manually at all.
What does the T::* mean? Also, is this not a function declaration? It looks like one, yet this compiles without defining a function body.
The int T::* is a pointer to member object. It can be used as follows:
struct T { int x; }
int main() {
int T::* ptr = &T::x;
T a {123};
a.*ptr = 0;
}
Once again, is this not a function declaration with no body ever defined? Also what does the ellipsis mean in this context?
In the other line:
template<class T> two test(...);
the ellipsis is a C construct to define that a function takes any number of arguments.
I would like to understand what this code is doing.
Basically it's checking if a specific type is a struct or a class by checking if 0 can be interpreted as a member pointer (in which case T is a class type).
Specifically, in this code:
namespace detail {
template <class T> char test(int T::*);
struct two{
char c[2];
};
template <class T> two test(...);
}
you have two overloads:
one that is matched only when a T is a class type (in which case this one is the best match and "wins" over the second one)
on that is matched every time
In the first the sizeof the result yields 1 (the return type of the function is char), the other yields 2 (a struct containing 2 chars).
The boolean value checked is then:
sizeof(detail::test<T>(0)) == 1 && !std::is_union<T>::value
which means: return true only if the integral constant 0 can be interpreted as a pointer to member of type T (in which case it's a class type), but it's not a union (which is also a possible class type).
Test is an overloaded function that either takes a pointer to member in T or anything. C++ requires that the best match be used. So if T is a class type it can have a member in it...then that version is selected and the size of its return is 1. If T is not a class type then T::* make zero sense so that version of the function is filtered out by SFINAE and won't be there. The anything version is used and it's return type size is not 1. Thus checking the size of the return of calling that function results in a decision whether the type might have members...only thing left is making sure it's not a union to decide if it's a class or not.
Here is standard wording:
[expr.sizeof]:
The sizeof operator yields the number of bytes occupied by a non-potentially-overlapping object of the type of its operand.
The operand is either an expression, which is an unevaluated operand
([expr.prop])......
2. [expr.prop]:
In some contexts, unevaluated operands appear ([expr.prim.req], [expr.typeid], [expr.sizeof], [expr.unary.noexcept], [dcl.type.simple], [temp]).
An unevaluated operand is not evaluated.
3. [temp.fct.spec]:
[Note: Type deduction may fail for the following reasons:
...
(11.7) Attempting to create “pointer to member of T” when T is not a class type.
[ Example:
template <class T> int f(int T::*);
int i = f<int>(0);
— end example
]
As above shows, it is well-defined in standard :-)
4. [dcl.meaning]:
[Example:
struct X {
void f(int);
int a;
};
struct Y;
int X::* pmi = &X::a;
void (X::* pmf)(int) = &X::f;
double X::* pmd;
char Y::* pmc;
declares pmi, pmf, pmd and pmc to be a pointer to a member of X of type int, a pointer to a member of X of type void(int), a pointer to a member ofX of type double and a pointer to a member of Y of type char respectively.The declaration of pmd is well-formed even though X has no members of type double. Similarly, the declaration of pmc is well-formed even though Y is an incomplete type.
template<typename T> T* Push(T* ptr);
template<typename T> T* Push(T& ref);
template<typename T, typename T1> T* Push(T1&& ref);
I have
int i = 0;
Push<int>(i);
But the compiler calls it ambiguous. How is that ambiguous? The second function is clearly the preferred match since it's more specialized. Especially since the T1&& won't bind to an lvalue unless I explicitly forward/move it.
Sorry - i is an int. Otherwise, the question would make no sense, and I thought people would infer it since it's normally the loop iterator.
If i is an int, then the first isn't viable. Last two remain. Then, for deduction of i, the second and the third both yield the same function types for overload resolution (both int& as parameter). So you have to rely on partial ordering.
However, partial ordering can't tell them apart. For a function call partial ordering context, only the parameters are used to determine an order (and the return type in your example is not considered), and any reference modifier is peeled off from them. So you will succeed deducing the parameter type from one against the other in both direction - both parameter types will be at least as specialized as the other parameters respectively. And neither has const applied, so neither is more specialized than the other.
There is an issue report placeholder that aims at clarifying anything related to rvalue/lvalue reference difficulties during partial ordering. See this usenet question for details.
If any of the two should be more specialized, i would say that it should the first one. After all, it accepts less arguments than the other one (the other one being a potential perfect forwarder).
Especially since the T1&& won't bind to an lvalue unless I explicitly forward/move it.
Actually, it will accept anything. Having a parameter of type T&& in a template will switch to the "perfect-forwarding-deduction-mode", which will deduce T to the type of the argument if it's an rvalue, and add a lvalue-reference modifier to the type of T if it's an lvalue. So if the argument is an lvalue, the resulting parameter type is T& && collapsed to T&, which accepts lvalues fine (just like in your case).
On a second look, what you seem to be trying to do is to overload a function for taking objects by moving them. But this won't work because of the special deduction done for T&& (see below). Just erase the first function and write your code as
template<typename T, typename T1> T* Push(T1&& ref) {
/* for lvalues, T1 is U& and rvalues it is U, with U being the
* argument type. */
T t1(std::forward<T1>(ref));
/* whatever needs to be done ... */
}
This will move-construct t1 if the argument was an rvalue, and copy ref if the argument was an lvalue or if T doesn't have a move constructor. This is just an illustration, it may not be what you actually should do depending on your real use-case. I'm also not sure why you have two template parameter types here. I propose to get rid of the T, and say typename remove_reference<T1>::type * for the return type, instead. So that you can gain from argument deduction.