I'd like to swap 2 values, pointed by iterators. So I want to specialize template function for taking iterators. Could you tell, please, how could I do this?
Function for non-iterators:
template <typename T>
void exch(T &a, T &b)
{
T c( std::move(a) );
a = std::move(b);
b = std::move(c);
}
Function for iterators:
template <typename It>
void exch(It &a, It &b)
{
auto c( std::move(*a) );
*a = std::move(*b);
*b = std::move(c);
}
Of course, with 2 functions I get an error:
/projects/DFSTL/main.cpp:17:6: error: redefinition of ‘template void exch(It&, It&)’
I would advise against doing this -- swapping a and b, and swapping the things indirectly referred to by a and b, is a tempting thing to overload. But you end up getting really strange behavior if you do that.
If you must, the first step would involve writing your own is_iterator traits class. This can be done through various methods. One that works on some compilers is to use SFINAE resolution of std::iterator_traits<It>::iterator_category, and check if input_iterator_tag or output_iterator_tag is a base of that type.
You do usually need to detect void* and cv variants. This is still implementation defined behavior, as std::iterator_traits on a non-iterator generates implementation defined results.
The more complex way is to examine each of the type axioms of iterators and test them, and if all pass say it is an iterator.
Once you have is_iterator<T>, you can use SFINAE:
template <class T, class=std::enable_if_t< !is_iterator<std::decay_t<T>>{} >>
void exch(T &a, T &b) {
using std::swap;
swap(a,b);
}
Function for iterators:
template <class It, class=std::enable_if_t< is_iterator<std::decay_t<It>>{} >>
void exch(It a, It b) {
using std::iter_swap;
iter_swap(a,b);
}
note that I called swap and iter_swap in an ADL-enabled context with std:: lookup rather than manually implementing it. This allows types that specialize their own swap in their enclosing namespace to automatically get their more optimal solution.
Both those template functions look identical to the compiler. That's why you get the compiler error.
Have you tried using this function: std::swap()?
It looks like it does what you want - and has been specialized for all STL container types for which a swap makes sense.
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)!
I'm trying to define a C++ concept for standard library containers that allow push_back/emplace_back:
template <class ContainerType>
concept PushBackContainer = requires(ContainerType a)
{
requires SequenceContainer<ContainerType>;
{ a.push_back(typename ContainerType::const_reference& v) };
{ a.push_back(typename ContainerType::value_type&& v) };
// How do you define a variable templated function:
{ template< class... Args > a.emplace_back(Args&&... args) };
}
The problem I have is how do I define emplace_back with its variadic template arguments? I'm using Visual Studio 2019 but if this isn't supported I'd be interested in the correct syntax come the time it is.
Probably about the best that's worth doing is just a.emplace_back();.
Your push_back requirements don't have a correct syntax, either. I think you want:
template <class ContainerType>
concept PushBackContainer = requires(
ContainerType& a,
typename ContainerType::value_type const& cv,
typename ContainerType::value_type& v)
{
requires SequenceContainer<ContainerType>;
a.push_back(cv);
a.push_back(std::move(v));
a.emplace_back();
};
Requirements don't check for a function signature; they check for the validity of an expression (without instantiating more templates than necessary). If we had a class like:
class StrangeContainer {
public:
using value_type = std::string;
using const_reference = const value_type&;
private:
struct ValueHolder {
ValueHolder(const std::string& s) : value(s) {}
ValueHolder(std::string&& s) : value(std::move(s)) {}
std::string value;
};
public:
void push_back(ValueHolder);
template <typename ... Args>
void emplace_back(Args&&...);
};
then ignoring SequenceContainer requirements, PushBackContainer<StrangeContainer> would be true, and it would also satisfy the Standard's own requirements related to push_back. It satisfies the technical requirements, even though it has some surprising effects like the fact that push_back("") is ill-formed.
So for push_back, we're really just checking that it can be called with a const lvalue and with a non-const rvalue. (The Standard actually also requires that it can be called with a non-const lvalue and with a const rvalue, and these cases have the same behavior as when called with a const lvalue.)
(If you really wanted to test for an exact push_back signature, you could try static_cast<void (ContainerType::*)(typename ContainerType::value_type&&)>(&ContainerType::push_back); - but this is not recommended, since member functions in namespace std are not required to have signatures exactly as described, only to be callable with the same arguments as if declared as described.)
Also, the standard container class templates don't have any constraints on their push_back or emplace_back functions. Every instantiation of the templates which have push_back declares both overloads, whether or not the type is copyable and/or movable. If not, it would be an error to actually call or otherwise odr-use the push_back function, but it "exists" for purposes of requires-expressions and SFINAE contexts. Likewise, the emplace_back member template is declared to accept any number of arguments with any types and value categories, no matter whether they can be used as value_type constructor arguments or not.
So what we would want to test to find out if the container has an emplace_back with an essentially ordinary variadic function declaration would need to be phrased as: Can emplace_back be called with any number of arguments, with each having any possible type and each being either an lvalue or rvalue? I don't think there's any way to really answer that within C++, using requires-expressions, SFINAE tricks, or otherwise. So I would just do one simple test for existence of some sort of emplace_back, and that test might as well be as simple as possible: zero arguments.
You could get fancier and also test for some additional cases: Does emplace_back accept different numbers of arguments, up to some fixed maximum? Does it accept lvalue and rvalue arguments? Does it accept arguments of dummy struct types? Dummy struct types that aren't MoveConstructible? const, volatile, and const volatile types? All possible combinations of all of the above? But since you'll never cover all the cases, how much value does each partial enhancement like this really give, compared to the effort, complexity, and maintenance needed to add checks?
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)!
No C++11 or Boost :(
I have a function with the following signature.
template<class INPUT_ITR, class OUTPUT_ITR>
void DoWork(const INPUT_ITR in_it, const INPUT_ITR in_it_end, OUTPUT_ITR out_it, OUTPUT_ITR out_it_end, CONTEXT_DATA)
Normally some complex processing takes place between the input and output.. but sometimes a no-op is required, and the data is simply copied. The function supports in-place operations if the input and output data types are the same. So I have this code.
if (NoOp)
{
if (in_it != out_it)
{
copy(in_it, in_it_end, out_it);
}
}
If an in-place operation has been requested (the iterator check), there is no need to copy any data.
This has worked fine until I call the function with iterators to different data types (int32 to int64 for example). Then it complains about the iterator check because they are incompatible types.
error C2679: binary '!=' : no operator found which takes a right-hand operand of type 'std::_Vector_iterator<std::_Vector_val<std::_Simple_types<unsigned __int64>>>
This has left me a bit stumped. Is there an easy way to perform this check if the data types are the same, but simply perform the copy if they are different types?
Thanks
You can extract the test into a pair of templates; one for matching types, one for non-matching types.
template <class T1, class T2>
bool same(T1 const &, T2 const &) {return false;}
template <class T>
bool same(T const & a, T const & b) {return a == b;}
Beware that this can give confusing results when used with types that you'd expect to be comparable. In C++11 (or with Boost, or a lot of tedious mucking around with templates) you could extend this to compare different types when possible; but that's beyond what you need here.
Also, note that you're relying on formally undefined behaviour, since iterators over different underlying sequences aren't required to be comparable. There is no way to tell from the iterators themselves whether this is the case.
I came up with a workaround. Any better suggestions welcome.
Overload the function to provide an in-place version. It's up to the user to request in-place now (in-place using the old function will perform the redundant copy in case of no op).
template<class ITR>
void DoWork(const ITR it, const ITR it_end, CONTEXT_DATA)
{
if (! NoOp)
{
DoWork(it, it_end, it, it_end, sSourceSpec, sDestSpec);
}
}
You could use std::iterator_traits and a custom is_same type trait since you don't have c++11:
template<class T, class U>
struct is_same
{
static const bool value = false;
};
template<class T>
struct is_same<T, T>
{
static const bool value = true;
};
if(!is_same<typename std::iterator_traits<INPUT_ITR>::value_type,
typename std::iterator_traits<OUTPUT_ITR>::value_type>::value)
{
copy(...);
}
How can I implement for instance the following
template <typename ITERATOR> void Swap (ITERATOR a, ITERATOR b) {
...
}
so that Swap(a, b) swaps the values pointed at by a and b.
In other words: How can I create a third variable without knowing the data type?
There is iter_swap just for that job:
std::iter_swap(a, b);
Also if you can use c++11 you can use decltype:
std::remove_reference<decltype(*a)>::type c = *a;
*a = *b;
*b = c;
How can I create a third variable without knowing the data type?
Use std::iterator_traits<ITERATOR>::value_type
In C++11, the type is std::remove_reference<decltype(*a)>::type, but for declaring a variable, you would use auto.
In C++03, the most reliable way to infer the type of any arbitrary expression is through another template:
// NOTE: This is for illustration only. If you are simply swapping
// values, use 'std::swap' instead of this, since that is specialised
// for many types to avoid unnecessary copy-assignment.
template <typename T> void value_swap(T & a, T & b) {
T t = a;
a = b;
b = t;
}
template <typename I> void iterator_swap(I a, I b) {
value_swap(*a, *b);
}
Alternatively, for well-behaved iterators (including pointers and standard iterators), the type is available as std::iterator_traits<ITERATOR>::value_type. This won't work if someone has written their own iterator type without either providing the nested types that the default iterator_traits requires or specialising iterator_traits for it.
Some compilers provide non-standard extensions similar to decltype; for example GCC provides typeof. You could use such a thing if you don't need your code to be portable.
By the way, your particular function already exists as std::iter_swap.
template <typename ITERATOR> void Swap (ITERATOR a, ITERATOR b) {
using std::swap;
swap(*a,*b);
}
The iterator has a so called trait defining it's value type.
iterator_traits<ITERATOR>::value_type temp = *a;
*a = *b;
*b = temp;