For simplicity, let's say I want to do implement a function which takes two parameters and predicate which test for equality,
template<typename T, typename TCompare>
bool Eq(const T& a, const T& b, const TCompare& cmp) {
return cmp(a, b);
}
but I also want that operator== is assumed if predicate is not passed.
I tried several different approaches, but all resulted in either syntax error or "operator==" not defined. I even tried replacing the Eq function with a
Nevertheless, I suppose what I want is possible since the big part of STL supports not passing the optional TCompare parameter (std::sort, std::set ...).
UPDATE:
Thanks to levis501 suggestion, this is the best way I have found so far:
template<typename T, typename TCompare>
bool Eq(const T& a, const T& b, const TCompare& cmp) {
return cmp(a, b); // or some lengthy code
}
template<typename T>
bool Eq(const T& a, const T& b) {
static std::equal_to<T> EqCmp;
return Eq(a, b, EqCmp);
}
So, you basically need to create a wrapper which passes std::equal_to, or any other operator-equivalent functor. For some reason, having it as a default argument does not compile when you invoke the function without it.
How about std::equal_to ? http://www.cplusplus.com/reference/std/functional/equal_to/
You can overload functions, no?
// Use the user-supplied TCompare.
template<typename T, typename TCompare>
bool Eq(const T& a, const T& b, TCompare cmp) {
return cmp(a, b);
}
// Use op== for equality otherwise.
template<typename T>
bool Eq(const T& a, const T& b) {
return a == b;
}
If the code calls Eq() with three arguments, the compiler will resolve the call to the first overload. If the code calls Eq() with only two arguments, then the compiler will have to resolve to the second overload.
I don't suppose something like the following would work for you:
#include <functional>
template<typename T, typename TCompare = std::equal_to<T>>
class Math {
public:
static bool Eq(const T& a, const T& b) {
TCompare cmp;
return cmp(a, b);
}
};
int _tmain(int argc, _TCHAR* argv[]) {
Math<int>::Eq(1,1);
return 0;
}
Default template parameters are only allowed on class templates (or at least that's what MSVC 10 says)
Related
I was trying to use a std::visit to access a member in a variant, and throw an error if that member wasn't available.
I was able to get a working solution but I found the errors in for my first two attempts unintelligible.
Does anybody know why "version 1" and "version 2" don't work?
#include <variant>
#include <vector>
#include <stdexcept>
struct a
{
int value=32;
};
struct b : a
{
};
struct c
{
//empty
};
using t = std::variant<std::monostate,a,b,c>;
struct wacky_visitor{
// Version 1 (doesn't work)
// bool operator()(const auto& l, const auto& r)
// {
// throw std::runtime_error("bad");
// };
// Version 2 (doesn't work)
// template <typename L, typename R>
// bool operator()(const L& l, const R& r)
// {
// throw std::runtime_error("bad");
// };
// Version 3 (works)
template <typename L, typename R>
std::enable_if_t<!(std::is_base_of_v<a, L> && std::is_base_of_v<a, R>), bool> operator()(const L& l, const R& r)
{
throw std::runtime_error("bad");
};
//Shared
template <typename L, typename R>
std::enable_if_t<std::is_base_of_v<a, L> && std::is_base_of_v<a, R>, bool> operator()(const L& l, const R& r)
{
return l.value < r.value;
};
};
int main()
{
std::vector<t> foo_bar = {a(),b()};
const auto comparison = [](const t &lhs, const t &rhs) {
return std::visit(wacky_visitor{}, lhs, rhs);
};
std::sort(foo_bar.begin(), foo_bar.end(), comparison);
return 0;
}
https://godbolt.org/z/1c488v
Your version 1 and version 2 mean exactly the same thing, so I'll only consider version 2.
When you invoke wacky_visitor, you have two overload choices:
// first overload
template <typename L, typename R>
bool operator()(L const&, R const&);
// second overload
template <typename L, typename R>
???? operator()(const L& l, const R& r)
Where the ???? is this enable_if "constraint" (I use quotes because it's the best C++17 could do as far as constraints go, but it's not a proper constraint, see below). In some cases, that's an invalid type, so the overload will be removed from consideration. But if it is a valid type, then... well, our two overloads are exactly the same. Both are exact matches in both arguments and there is nothing whatsoever to distinguish them.
Your 3rd version works because the negated enable_if condition ensures that exactly one of the two overloads is viable, so overload resolution always has exactly one candidate to choose from -- which then becomes trivially the best.
It's easier to just use if constexpr and have a single overload:
template <typename L, typename R>
bool operator()(const L& l, const R& r)
{
if constexpr (std::is_base_of_v<a, L> && std::is_base_of_v<a, R>) {
return l.value < r.value;
} else {
throw std::runtime_error("bad");
}
};
In C++20, Concepts has the added functionality that a constrained function template is preferred to an unconstrained one. Which means you could write it like this:
// first overload as before, whichever syntax
template <typename L, typename R>
bool operator()(L const&, R const&);
// second overload is now constrained
template <typename L, typename R>
requires std::is_base_of_v<a, L> && std::is_base_of_v<a, R>
bool operator()(const L& l, const R& r);
If the 2nd overload isn't viable, the 1st one is called -- as before. But now, if the 2nd overload is viable, it is able to be preferred to the 1st anyway.
The second overload can also be written like this:
template <std::derived_from<a> L, std::derived_from<a> R>
bool operator()(const L& l, const R& r);
Which means approximately the same thing.
In a template function a std::vector shall get sorted. T can be a simple type or a std::pair e.g.,
std::vector<double> or
std::vector<std::pair<int,Something> >
When T is a pair then only the first element shall be compared. How can I implement the comparator for the two cases?
I have tried:
template<typename T>
inline bool smaller(const T& a,const T& b)
{
return a<b;
}
template<typename T,typename S>
inline bool smaller(
const std::pair<T,S>& a,
const std::pair<T,S>& b
)
{
return a.first<b.first;
}
template<typename T> inline void function(std::vector<T >& vVec)
{
...bla...
sort(vVec.begin(),vVec.end(),smaller<T>);
...bla...
}
but it does not work this way. I have also tried specialization but I do not find the right syntax to specialize the smaller() function.
You could just wrap it in a lambda:
std::sort(vVec.begin(),vVec.end(), [](const auto& a, const auto& b) { return smaller(a, b); });
One easy work around is to make both of your smaller functions opeator()'s of a smaller struct. Using
struct smaller
{
template<typename T>
bool operator()(const T& a,const T& b)
{
return a < b;
}
template<typename T, typename S>
bool operator() (const std::pair<T, S>& a, const std::pair<T, S>& b)
{
return a.first < b.first;
}
};
allows you to just pass a smaller to sort like
template<typename T> inline void function(std::vector<T >& vVec)
{
sort(vVec.begin(),vVec.end(),smaller{});
}
and in sort overload resolution will kick in on the two operator() smaller has and for any std::vector<std::pair>, the std::pair overload will be called.
For example, if I have the following variant and a static_visitor:
typedef boost::variant<long, int, float, double> DataType;
And I'd like this to work:
DataType x(1.2);
DataType y(100);
std::cout<<boost::apply_visitor(Multiply(), x, y)<<std::endl; // should return 120
with a visitor like this:
struct Multiply : public boost::static_visitor<DataType>
{
template<typename T, typename U>
DataType operator()(const T& a, const U& b) const
{
// what to do here??
}
template<typename T>
DataType operator()(const T& a, const T& b) const
{
return a * b;
}
};
How I can do this without having to list all the possible combinations of types in the Multiply visitor?
My advice: Don't special-case on same type, but on multiplyability:
struct Multiply : public boost::static_visitor<DataType> {
template<typename T, typename U>
static auto operator()(const T& a, const U& b) const
-> decltype(DataType(a*b)){
return a*b;
}
template<typename... Ts>
static DataType operator()(const Ts... params) const {
throw std::invalid_argument("can't multiply");
}
};
Changes:
No special-casing of any combination which works.
Throwing an exception on any combination which does not.
Now static.
Uses expression-SFINAE to decide.
Still, it won't return 120 for your example, because binary floating-point cannot represent 1.2 exactly.
I'm working in C++98 and I want to bind std::max. But I need a functor object to use with std::bind1st.
I've tried just using std::pointer_to_binary_function but the problem seems to be that I can't make a functor out of std::max: https://stackoverflow.com/a/12350574/2642059
I've also tried std::ptr_fun but I get a similar error.
Because of the issue in this answer, you can't write a true wrapper functor for max because you can't make any of the types const T&. The best you can do is:
template <typename T>
struct Max
: std::binary_function<T, T, T>
{
T operator()(T a, T b) const
{
return std::max(a, b);
}
};
std::bind1st(Max<int>(), 1)(2) // will be 2
But that sucks, since you now have to copy everything (although if you're just using ints, this is totally fine). Best would probably be to just avoid bind1st altogether:
template <typename T>
struct Max1st
{
Max1st(const T& v) : first(v) { }
const T& operator()(const T& second) const {
return std::max(first, second);
}
const T& first;
};
I have the following code:
// string specializations
void foo(const char *a, const char *b);
void foo(const char *a, const std::string &b);
void foo(const std::string &a, const char *b);
void foo(const std::string &a, const std::string &b);
// generic implementation
template<typename TA, typename TB>
void foo(TA a, TA b)
{...}
The problem is that this test case:
char test[] = "test";
foo("test", test);
ends up calling the templated version of foo. Obviously, I can just add a few more overloads with various mixes of non-const parameters, but I want to know: is there's a better way to overload foo such that it is specialized on all const and non-const pairings of strings? One that doesn't require me to hope I haven't missed some permutation of argument types?
Thanks to Mooing Duck's suggestion, this is my solution:
// string specialization
void foo(const std::string &a, const std::string &b);
template<typename TA, typename TB>
typename std::enable_if<
std::is_constructible<std::string, TA>::value &&
std::is_constructible<std::string, TB>::value
>::type foo(TA a, TB b)
{
foo(std::string(std::move(a)), std::string(std::move(b)));
}
// generic implementation
template<typename TA, typename TB>
typename std::enable_if<
!std::is_constructible<std::string, TA>::value ||
!std::is_constructible<std::string, TB>::value
>::type foo(TA a, TB b)
{...}
If I understand your goals properly you could do this
template<typename T1,typename T2 >
void foo(T1, T2)
{
static_assert(sizeof(T1) == 0,"Did not overload all foo's");
}
template<>
void foo<const char *a, const char *b>()
{
... Handle this case
}
... ect ect ect
This has the advantage of you handling every instance you want explicitly while generating a compilation error if you missed one.