HI,
I started learning C++ STL's
i am just trying some small programs.one of them is below:
inline int const& max (int const& a, int const& b)
{
return a < b ? b : a;
}
template <typename T>
inline T const& max (T const& a, T const& b)
{
return a < b ? b : a;
}
int main()
{
::max(7, 42); // calls the nontemplate for two ints
::max<>(7, 42); // calls max<int> (by argument deduction)
::max('a', 42.7); // calls the nontemplate for two ints
}
I have some basic questions!!
why is the scope resolution
operator used here?
why/how is
that calling ::max<>(7, 42) will
assume that the parameter passed are
integers?
1) why is the scope resolution
operator used here?
Probably to differentiate the max declared here from the one in (for example) the std:: namespace.
2) why/how is that calling ::max<>(7, 42) will assume that the
parameter passed are integers?
It doesn't have to assume anything - integer literals have the type int.
And to answer the question you didn't ask:
max('a', 42.7);
matches the non-template version because type conversions are not performed on templated parameters, but are performed on non-template ones.
Presumably to avoid conflicts with std::max
It's not assuming that the parameters are integers, it sees that the parameters are integers. It then assumes that the template argument is int because the parameters are integers.
For 2) what you possible mean is that why does it work - the template does not require integers, just any types on which the "<" operator is defined. An integer fulfills this so it is ok to pass it to the template method.
Related
I have a problem with constant single element std::vector when pass through a function. C++ compiler automatically call wrong function when the std::vector variable contain a single element. This is though the policy of C++ design. However is there any explicit method to specify in such a case. Here are the examples of the problems
assume i have two overload functions both have the same name "foo"
void foo(const std::vector<int> A)
{
// do vector operator
printf("vector thing");
}
void foo(int a)
{
// do integer operator
printf("integer thing")
}
In general case both of these functions are called correctly
foo({1,2,3}); // print do vector thing
foo( 3 ); // print do integer thing
however from c++ rule. when call
foo({5}); // print do integer thing ( I want it to call as vector )
one of the methods is to create a variable
std::vector<int> B = { 5 };
in order to solve this problem.
I feel this method is a bit clumsy. Is there any method that can void the compiler to treat {5} as 5 and call foo(int a).
note:
here is the reference that explain what the problem is
c++11 single element vector initialization in a function call
You need another overload, taking std::initializer_list as a parameter:
void foo(std::initializer_list<int> A)
{
foo(std::vector<int>(A.begin(), A.end()));
}
If you always call this function by creating vectors directly with {...}, rather than using std::vector variables, then you can remove std::vector overload completely and operate directly on std::initializer_list.
No, because as of C++17 the rules explained on the linked answer still hold.
You can create a temporary instead of a variable, though.
foo(std::vector{5}); // C++17 with class type deduction
foo(std::vector<int>{5}); // older versions
One way to disambiguate the function call is to make the integer overload a function template:
template <class Int> void foo(Int a)
{
std::printf("generalized (maybe integer) thing\n");
}
This way, the invocation
foo({3});
will consider the non-templated function a better match while foo(3) instantiates and calls the function template. This because {3} is an std::initializer_list<int> with one element in the context of type deduction. You can also redirect to the original foo(int a) function like this:
void fooImpl(int a)
{
std::printf("integer thing\n");
}
template <class Int> void foo(Int&& a)
{
fooImpl(std::forward<Int>(a));
}
This refuses to compile when e.g. calling foo with an argument not convertible to an integer, which might be a desirable usage restriction. Also, it should be very unlikely that you encounter a performance overhead due to the forwarding intermediate function.
I have a bubble-sort function that takes an array, a compare function, and a boolean that indicates if it should sorts the array upside-down. It is a template function that supports any data-type, and will deduce array size automatically.
When specifying the compare function, if I pass function pointer, the compiler will deduce the data type of array automatically, which is great. But if I pass a lambda instead, it will not deduce automatically. I have to specify the data type explicitly, or static_cast the lambda as fnCompare_t<double>.
What is the reason behind this? Because according to this post, as long as the lambda doesn't capture, it can be used like the plain-old function pointer, but it seems it is not always the case? How come it can be different in this case?
#include <iostream>
using namespace std;
template <typename T>
using fnCompare_t = int(*)(T const &, T const &);
template <typename T, size_t count>
inline void BubbleSort(
T(&array)[count],
fnCompare_t<T> fnCompare,
bool reverse)
{
cout << "TODO: Implement BubbleSort" << endl;
}
double doubleArray[] = {
22.3, 11.2, 33.21, 44.2, 91.2, 15.2, 77.1, 8.2
};
int CompareDouble(double const & a, double const & b)
{
return a > b ? 1 : a == b ? 0 : -1;
}
int main()
{
auto fnCompare = [](double const & a, double const & b) -> int {
return a > b ? 1 : a < b ? -1 : 0;
};
// compile OK:
BubbleSort(doubleArray, CompareDouble, false);
BubbleSort(doubleArray, static_cast<fnCompare_t<double>>(fnCompare), false);
BubbleSort<double>(doubleArray, fnCompare, false);
// compile error, could not deduce template argument:
//BubbleSort(doubleArray, fnCompare, false);
return 0;
}
The reason why is because you can't get an implicit conversion on a templated parameter when using deduction. The classic example is:
template <class T>
T min(T x, T y);
Calling this function as min(1, 3.0) will result in a failure. Because for both arguments, it tries to find a T to get a perfect match, and fails. If you specify the template parameter explicitly it can work: min<double>(1, 3.0). The same is true in your example, if you specify T explicitly it will work.
The idiomatic way to write the signature for your function is:
template <typename Iter, typename F>
inline void BubbleSort(
Iter b, Iter e,
F fnCompare,
bool reverse)
However, this discards the compile time length information. If you want to keep that, you can do:
template <typename T, size_t count, typename F>
inline void BubbleSort(
T(&array)[count],
F fnCompare,
bool reverse);
Though you should at least consider using std::array instead of a C style array which will make the signature a bit less ugly and has other benefits.
This may seem odd as we are not "verifying" the comparator having the correct signature, in the signature of our sort. But this is normal in C++, if the comparator is incorrect then it will fail at the point of usage and it will still be a compile time error. Note as well when you try to depend on a lambda implicitly converting into a function pointer, you are being unnecessarily restrictive: lambdas only convert into function pointers with identical signature. Even if the output of the lambda is implicitly convertible to the output of the function pointer, your lambda will not implicitly convert, even though the lambda can still be used!
As a final final note, it's usually better to pass functors because it's better for performance. Comparators are usually small functions and often will get inlined. But in your version, the comparator will not typically be inlined, in mine it will (because I preserve the original type of the lambda, and you do not).
You need to explicitly cast the lambda to a function pointer. There is no other way around it. But, instead of static_casting you can apply + to the lambda, which would trigger the function pointer conversion, as you can apply + to a pointer type:
BubbleSort(doubleArray, +fnCompare, false);
// ^^
// applying unary + invokes the function pointer conversion operator
The reason for why there is no implicit call to the conversion operator is that during overload resolution, the compiler will only consider templates that match perfectly (see this for more info). Because a lambda is not a function pointer, there cannot be a perfect match, and the overload is discarded.
I read that function call () can also be overloaded. http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B
What would the following mean?
It works.
template<typename T, typename Comp>
struct bind{
T v;
Comp comp;
bool operator()(const T& b){
return comp(b,v);
}
};
int main(){
bind<int, less<int> > b;
b.v = 2;
cout << b(3) << "\n";
}
It means that if you create an object of type bind<>, you can apply the function-call operator to that object.
Like this:
bind<int, std::less<int>> b;
b.v = 2;
std::cout << b(1) << "\n";
That snippet might print "true" on the standard output.
If you have a class called foo, I'm sure you understand what it means to call a member function of an object of that type:
foo f;
f.bar();
You may also understand that you can overload certain operations. For example, you could overload operator+ for foo so that you could do something like this:
foo f, g;
f + g;
Now you can also overload operator() for a class, which allows you to call it as though it were a function:
foo f;
f();
Yes, f is not a function but it is an object of class type that overloads operator(). Class types that do this are known as functors or function objects.
In the example you've given, bind is a functor. When you create an object of that type, you can call it like a function, passing it a const T& and it will return a bool back to you. The implementation of operator() actually calls the function stored in comp, passing it both the T object you passed to operator(), a, and the member object v of type T.
As it stands, it doesn't mean much of anything except "syntax error". For example:
template<T, Op>
This simply isn't allowed. For each template parameter, you need to specify whether it's a type (using class or typename) or a non-type parameter such as an int. Since the apparent intent is that both these should be type parameters, you need something like:
template <class T, class Op>
or:
template <typename T, typename Op>
For this situation, there's no difference in meaning between class and typename.
struct bind{
T v;
Leaving v uninitialized will lead to undefined behavior, so you probably don't want to allow that. You'd normally prevent it by adding a constructor that takes a T as its parameter and initializes v to that value:
bind(T const &v) : v(v) {}
When you include a constructor like this, the compiler won't automatically generate a default constructor, so it's no longer possible to create a bind object with v uninitialized -- exactly what we wanted.
Although creating the comp object:
Op comp;
is fairly harmless, it's also quite unnecessary. You could just as well do the comparison with a temporary instance created with Op(), in which case this:
bool operator()(const T& a){
return comp(a,v);
}
...would become something like this (and the Op comp; simply removed):
bool operator()(T const &a) {
return Op()(a, v);
}
Even with the corrections, I'd consider this code obsolescent. In C++98/03, it would have been useful in a situation where you needed to supply a functor to an algorithm, such as:
std::remove_copy_if(a.begin(), a.end(), bind<int,
std::back_inserter(b),
bind<int, std::less<int> >(5));
...which would copy numbers from a to b, removing those less that 5.
In C++11, however, most (if not all) uses of this bind should probably be written as lambdas instead though, so the bit above would become something like:
std::remove_copy_if(a.begin(), a.end(), bind<int,
std::back_inserter(b),
[](int x) { return x < 5; });
This is not only shorter, but (at least once you're used to it) quite a bit simpler than using std::less and bind to put together a function. It won't generally make any difference in run-time efficiency -- a lambda is basically a "shorthand" way of generating a class template, so what it generates would end up pretty similar to the code using bind.
struct S(int a, int b) { }
void fun(T)(T t) { }
I want fun to work with S only. What would the signature constraint look like?
I can't make fun a member of S, and with void fun(T)(T t) if(is(T : S)) { } I get Error: struct t1.S(int a,int b) is used as a type
S is not a type. It's a template for a type. S!(5, 4) is a type. It's quite possible that different instantiations of S generate completely different code, so the definition of S!(5, 4) could be completely different from S!(2, 5). For instance, S could be
struct S(int a, int b)
{
static if(a > 3)
string foo;
static if(b == 4)
int boz = 17;
else
float boz = 2.1;
}
Note that the number and types of the member variables differ such that you can't really use an S!(5, 4) in place of an S!(2, 5). They might as well have been structs named U and V which weren't templatized at all for all of the relation that they really have to one another.
Now, different instantiations of a particular template are generally similar with regards to their API (or they probably wouldn't have been done with the same template), but from the compiler's perspective, they have no relation with one another. So, the normal way to handle it is to use constraints purely on the API of the type and not on its name or what template it was instantiated from.
So, if you expect S to have the functions foo, bar, and foozle, and you want your fun to use those functions, then you'll construct a constraint that tests that the type that's given to fun has those functions and that they work as expected. For instance
void fun(T)(T t)
if(is({ auto a = t.foo(); t.bar(a); int i = t.foozle("hello", 22);}))
{}
Then any type which has a function called foo which returns a value, a function named bar which may or may not return a value and which takes the result of foo, and a function named foozle which takes a string and an int and returns an int will compile with fun. So, fun is far more flexible than if you had insisted on it taking only instantiations of S. In most cases, such constraints are separated out into separate eponymous templates (e.g. isForwardRange or isDynamicArray) rather than putting raw code in an is expression so that they're reusable (and more user friendly), but expressions like that are what such eponymous templates use internally.
Now, if you really insist on constraining fun such that it only works with instantiations of S, then there are two options that I'm aware of.
1. Add a declaration of some kind which S always has and you don't expect any other type to have. For instance
struct S(int a, int b)
{
enum isS = true;
}
void fun(T)(T t)
if(is(typeof(T.isS)))
{}
Note that the actual value of the declaration doesn't matter (nor does its type). It's the simple fact that it exists that you're testing for.
2. The more elegant (but far less obvious solution) is to do this:
struct S(int a, int b)
{
}
void fun(T)(T t)
if(is(T u : S!(i, j), int i, int j))
{}
is expressions have a tendancy to border on voodoo once they get very complicated, but the version with commas is precisely what you need. The T u is the type that you're testing and an identifier; the : S!(i, j) gives the template specialization that you want T to be an instantiation of; and the rest is a TemplateParameterList declaring the symbols which are used in the stuff to the left but which haven't previously been declared - in this case, i and j.
I think there are a couple of small red herrings in the other answers. You can use pattern matching to figure whether T is some instance of S, as follows.
Simplest way is to just pattern-match the argument itself:
void fun(int a, int b)(S!(a, b) t) {
}
More generally you can pattern-match in separation, inside a template constraint:
void fun(T)(T t) if (is(T U == S!(a, b), int a, int b)) {
}
In both cases you have access to the instantiation arguments.
"Work with S only" doesn't really make sense in D, because
S is not a type, it's a template.
A template is itself "something" in D, unlike in other languages.
What you wrote is a shorthand for:
template S(int a, int b) { struct S { } }
So the type's full name is S(a, b).S, for whatever a or b you use. There's no way to make it "generically" refer to S.
If you need to put a constraint like this, I suggest putting something private inside S, and checking that T has the same member.
I got a simple C++ struct as follows:
// Functor for peak to decreasing intensity sorting
struct cmp_decr_int2
{
bool operator() (peak2 a, peak2 b)
{
return a.int2 > b.int2;
}
};
is there an overload of the operator in this sample?
Yes. operator() is called the "function call" operator, and allows an object to be usable as if it were a function. Such a class is called a "functor".
A common pattern is to make functors that compare two things for equality or relations, for use in anything requiring a comparison predicate. (This one could be usable in an std::map, for example. It would have a member likecmp_decr_int2 compare; and then it could compare the relation between two things with: if (compare(x, y)) /* x is less than y, by some metric */)
This particular struct orders two peak2's by comparing their int2 members. It could be better written as:
struct cmp_decr_int2
{
// note const! vvvvv
bool operator() (peak2 a, peak2 b) const
{
return a.int2 > b.int2;
}
};
The function should be const because it does not need to change any members (there are none to change.) const-correctness is important.*
In many cases these functors are used in contexts where the arguments themselves are const, so you should either take the arguments by value as in the example or by constant reference.
You should prefer to pass types by const-reference over by-value, except when that type is fundamental (float, unsigned int, double, etc.) or smaller than a void*. In most cases, then, you will pass by const-reference:
struct cmp_decr_int2
{
// note const&: vvvvv v vvvvv v vvvvv
bool operator() (const peak2 & a, const peak2 & b) const
{
return a.int2 > b.int2;
}
};
*If this were used as a predicate in a std::map, for example, without const the map wouldn't be able to compare two things while within a const function.
Structs in C++ are just classes with a default accessor of public instead of private. So yes, that would have a function overload.
in c++ a struct is in every way like a class, except that the default parameter access is public: rather than private:. It is a common practice to use struct instead of class when the scope of the defined type's use is very narrow, such as in the example of a simple functor.
What this example does is emulate the appearance of a function pointer without the fragility of possibly being null.
The operator() member here overloads function calling. when you try to do something like:
cmp_decr_int2 foo;
foo(peek2(), peek2());
that overload member gets called.
#include <iostream>
using namespace std;
struct cmp_decr_int2
{
bool operator() (int a, int b)
{
return a > b;
}
bool operator() (int i)
{
return i > 0;
}
};
int main()
{
cmp_decr_int2 a;
cout << a(1, 2) << endl;
cout << a(1) << endl;
}
Yep, sure can overload the function! This worked perfectly for me.
$13.5.4 states-
operator() shall be a non-static member function with an arbitrary number of parameters. It can have default arguments. It implements the function call syntax postfix-expression ( expression-listopt ) where the postfix-expression evaluates to a class object and the possibly empty expression-list matches the parameter list of an operator() member function of the class. Thus, a call x(arg1,...) is interpreted as x.operator()(arg1, ...) for a class object x of type T if T::operator()(T1, T2, T3) exists and if the operator is selected as the best match function by the overload resolution mechanism (13.3.3).
Therefore, the struct 'cmp_decr_int2' has definitely overloaded operator().
Note that this is also the only operator in C++ that can take variable number of arguments.