I need a function that will take two iterators and a custom comparator to compare values of this iterators. I don't want use additional template argument for this. I've implemented it in this way:
template<typename T>
void foo(T begin, T end,
function<bool(decltype(*begin), decltype(*begin))> compare = less<decltype(*begin)>())
{
// I want to use 'compare' as: "compare(*begin, *begin);"
}
This code has been compiled normally by clang, but on GCC 5.4.0 I've got some errors:
binary_heap.cpp:10:79: error: local variable 'begin' may not appear in this context
function<bool(decltype(*begin), decltype(*begin))> compare = less<decltype(*begin)>())
^
binary_heap.cpp:10:85: error: template argument 1 is invalid
function<bool(decltype(*begin), decltype(*begin))> compare = less<decltype(*begin)>())
How to correct this code so that it can be successfully compiled on both clang and GCC? Or maybe are there a more suitable solution for defining such function?
You cannot use a parameter in a default argument, even in an unevaluated context (although the Standard should probably be amended to loosen that restriction). Instead of decltype(*begin), use
decltype(*std::declval<T&>())
Edit: Actually, that probably doesn't do what you want, since if applying the * operator yields an lvalue, then the decltype specifier will resolve to an lvalue reference, but you would want the unreferenced type to be the argument to std::less. Better to use:
typename std::iterator_traits<T>::value_type
Edit 2: I agree with krzaq, it's better to just add another template parameter.
You're pessimizing performance of your algorithm by a lot just by forcing the use of function (more details here). Just take template deduced Compare and you're golden:
template<typename T, typename Compare = std::less<typename iterator_traits<T>::value_type>>
void foo(T begin, T end, Compare compare = {})
{
// I want to use 'compare' as: "compare(*begin, *begin);"
}
Interestingly, standard algorithms force/suggest use of lightweight functors by taking them by value instead of a forwarding reference.
To answer the actual question: you can use std::less<>, which defaults to std::less<void> and has templated operator() doing the actual comparisons:
template<typename T>
void foo(T begin, T end,
function<bool(decltype(*begin), decltype(*begin))> compare = less<>())
{
// I want to use 'compare' as: "compare(*begin, *begin);"
}
Add another template parameter Compare. This makes inlining easier by the compiler. While I'm at it support Sentinels.
template<class It, class Sentinel, class Compare=std::less<void>>
void foo(It begin, Sentinel end, Compare cmp={}) {
}
However, assuming C++14, barring the above, I'd do this:
template<class T>
using comparator_sig = bool(T const&,T const&);
template<class T>
using comparator = std::function<comparator_sig<T>>;
template<class It>
using compare_inside_it = comparator<
typename std::iterator_traits<It>::value_type
>;
template<typename T>
void foo(T begin, T end, compare_inside_it<T> compare = less<>) {
}
in C++11 I would write my own less<void>:
struct compare_less {
template<class T>
bool operator()( T const& lhs, T const& rhs ) const {
return std::less<T>{}(lhs, rhs);
}
};
and do:
template<typename T>
void foo(T begin, T end, compare_inside_it<T> compare = compare_less{}) {
}
or even just do:
template<typename T>
void foo(T begin, T end, compare_inside_it<T> compare = {}) {
if (!compare) compare=compare_less{};
}
Related
I write interfaces through concepts for implementation validation.
There are no problems with conventional methods:
// Interface realization
struct Realization
{
int* TestMethod(const std::string& aStr)
{
return (int *) aStr.c_str();
}
};
// Concept
template <typename T>
concept IRealization = std::is_same_v<decltype(&T::TestMethod), int* (T::*)(const std::string&)>;
// and then, for example
void Check()
{
static_assert(IRealization<Realization>)
}
but when I try to write a similar check for a template method:
// Interface realization
struct Realization
{
template <typename T>
int* TemplateMethod(const T& aStr)
{
return (int *) aStr.c_str();
}
};
, I run into a problem of dectype a template method, because I cant write
decltype(&RealizationImpl::TemplateMethod)
(at the time of checking the interface, I do not know the type that will be substituted)
Please tell me, can I somehow get the signature of the template function without type, or otherwise solve my problem? Thanks!
You should not write concepts like this. A concept should never check for something as specific as a member function with an exact signature. A concept should instead say that, given an instance of the type in question, I should be able to do i.memberFunc(...), where ... is the list of parameters.
For example, your "IRealization" concept (please don't prefix concepts with I. Concepts are not interfaces) ought to say "T must have a member function which can be called given a std::string argument and results in something which is convertible to an int." That would look like:
template <typename T>
concept IRealization = requires(T t, std::string str)
{
{ t.TestMethod(str) } -> convertible_to<int>;
};
This allows the user to provide a TestMethod that takes, for example, std::string_view instead of std::string. There's no point in being so incredibly restrictive on the type.
A concept that checks for T having a member function which is callable with some type U would have to be templated on both T and U:
template <typename T, typename U>
concept IRealization = requires(T t, U u)
{
{ t.TestMethod(u) } -> convertible_to<int>;
};
What is the problem with adding another type to the concept?
// Concept
template <typename T, typename U>
concept IRealization = std::is_same_v<decltype(&T::template TestMethod<U>), int* (T::*)(const U&)>;
For instance.
You could even make it prettier by creating a typedef -
template<typename T, typename U>
using FuncT = decltype(&T::template TestMethod<U>);
For example, I want to implement my own generic sort function, I want to require the type that would be passed in to be Indexable, and the element inside would be Comparable
template <typename Cont>
**type_check: Cont is Indexable, Cont::Element is Comparable**
void my_sort(Cont& cont){
// do sorting work
}
When I do my_sort(vector<int>{1,6,5,4}) would be okay
But when do my_sort(linkedlist<int>{1,6,5,4}) would fail me at Compile/Runtime, because linkedlist is not Indexable.
So is there a way to do such kind of type contract programming?
P.S. I am in C++ 11 environment, but any Solution in later version of C++ is also welcomed
With SFINAE you can do something like:
template <typename Cont>
auto my_sort(Cont& cont)
-> decltype(cont[42], // Indexable
void(), // That void to avoid evil overload of operator comma
std::declval<Cont::Element>() < std::declval<Cont::Element>(), // Comparable
void()) // That final void for the return type of sort
{
// do sorting work
}
std::enable_if is an alternative (to the decltype) if you have the traits ready.
As mentioned in the comments, once the Concepts TS makes its way into the C++ standard, you'll be able to do this with something like:
template <typename T>
concept Sortable = requires(T t) {
{ t[0] < t[0] } -> bool
};
template <Sortable Cont>
my_sort(Cont& cont) {
// do sorting work
}
Live Demo
An older version of the Concepts TS is implemented by GCC with the -fconcepts flag, but it won't be in the standard until C++20. Until then, you can make do with SFINAE tricks:
template <typename Cont>
std::enable_if_t<std::is_convertible_v<decltype(std::declval<Cont>()[0] < std::declval<Cont>()[0]), bool>>
my_sort(Cont& cont) {
// ...
}
This will fail to compile if, for a given Cont c, c[0] < c[0] is either not valid or not convertible to bool.
Live Demo
I have problem similar to Passing different lambdas to function template in c++ but now with wrappers created by std::bind instead of lambdas.
I have two overloads of method Add that take different forms of std::function:
template<typename T>
struct Value
{
T value;
};
template <typename T>
void Add(Value<T> &value, function<bool()> predicate)
{
}
template <typename T>
void Add(Value<T> &value, block_deduction<function<bool(const Value<T> &)>> predicate)
{
}
This now works fine with lambdas but fails with functors bound with std::bind:
struct Predicates
{
bool Predicate0() { return true; }
bool Predicate1(const Value<int> &) { return true; }
};
Predicates p;
Add(i, std::bind(&Predicates::Predicate0, &p));
fails with
error C2668: 'Add': ambiguous call to overloaded function
and
Add(i, std::bind(&Predicates::Predicate1, &p, _1));
fails with static assert (Visual C++ 2015, Update 3):
tuple index out of bounds
Is there a way to make it work both with lambdas and bound functors? I would think of using SFINAE to enable the individual overload based on is_bindable_expression and checking the argument type but I'm failing to put it together.
Stop using std::bind. It is a mess of random features and quirks.
Todays quirk is that std::bind will accept an unlimited number of arguments and discard any extra ones. Tomorrow you might run into the fact that passing std::bind result to std::bind does strange magic.
std::bind was ported over to boost at the same time lambdas where added to the language. Lambdas solve almost every problem bind does in just as clear syntax and fails to have the myraid of quirks bind does, especially post C++14 when auto lambdas are available. (Most C++11 compilers also supported auto lambda).
You can write functions so that one or the other is the preferred overload when they both apply. But doing so adds a pile of noise to your interface, and in this case about the only reason why you'd want that preference is because std::bind is doing something stupid.
Engineering around a poorly designed bit of std library is not worth it. Simply stop using that poorly designed bit of std library, or at point of use cast explicitly.
Failing that, do this:
template <class T, class F,
std::enable_if_t<
std::is_convertible<
std::result_of_t<std::decay_t<F> const&(Value<T> const&)>,
bool
>{}, int
> = 0
>
void Add(Value<T> &value, F&& f)
{
// do pass f Value<T>
}
template <class T, class F,
std::enable_if_t<
!std::is_convertible<
std::result_of_t<std::decay_t<F> const&(Value<T> const&)>,
bool
>{}
&& std::is_convertible<
std::result_of_t<std::decay_t<F> const&()>,
bool
>{}, int
> = 0
>
void Add(Value<T> &value, F&& f)
{
// do not pass f Value<T>
}
where we throw some nasty SFINAE detection on which of the two overloads you want to use, and explicitly prefer one.
This is not worth it.
I don't think you can do what you want.
You can use is_bind_expression to check if your argument is a type produced by a call to std::bind, but there is no way to tell how many arguments the callable expects. As cpplearned mentioned in the comments, this is a feature of std::bind:
If some of the arguments that are supplied in the call to g() are not
matched by any placeholders stored in g, the unused arguments are
evaluated and discarded.
That means that both overloads are equally valid.
If you don't mind sharing the same overload for all bind results, you can pass all the parameters and let them be discarded at will:
template <typename T>
void AddImpl(Value<T> &value, function<bool()> predicate, std::false_type)
{
predicate();
}
template <typename T>
void AddImpl(Value<T> &value, block_deduction<function<bool(const Value<T> &)>> predicate, std::false_type)
{
predicate(value);
}
template <typename T, typename U>
void AddImpl(Value<T>& value, U&& bind_expression, std::true_type)
{
bind_expression(value);
}
template<typename T, typename U>
void Add(T&& t, U&& u)
{
AddImpl(std::forward<T>(t), std::forward<U>(u), std::is_bind_expression<std::decay_t<U>>{});
}
demo
But this is similar to using boolean parameters. In my opinion it'd be better for readability to dispatch on properly named tags:
template <typename T>
void AddImpl(Value<T> &value, function<bool()> predicate, tag::default_)
{
predicate();
}
template <typename T>
void AddImpl(Value<T> &value, block_deduction<function<bool(const Value<T> &)>> predicate, tag::default_)
{
predicate(value);
}
template <typename T, typename U>
void AddImpl(Value<T>& value, U&& bind_expression, tag::bind)
{
bind_expression(value);
}
template<typename T, typename U>
void Add(T&& t, U&& u)
{
AddImpl(std::forward<T>(t), std::forward<U>(u), tag::get_tag<std::decay_t<U>>{});
}
with tags defined as
namespace tag
{
struct default_{};
struct bind{};
template<typename T, typename = void>
struct get_tag : default_ {};
template<typename T>
struct get_tag<T, std::enable_if_t<std::is_bind_expression<T>::value>> : bind {};
}
demo
I have a function template which takes a templated parameter:
template <class R>
RefT<R> make_ref(R& res) {
return RefT<R>(&res);
}
I either want to prevent R from being any kind of iterator, or, if this is easier, I want to have a overload that the compiler will prefer to use for iterators which calls make_ref again with the iterator dereferenced.
Best approach would be combining the two, so the compiler prefers using iterator specific overload, and refuses to use the non-specific version.
I would like consumers of the code to be able to call make_ref(something) without having to think about whether the something is an iterator or not - I just need to do something different if it is, and if that's not possible, give a useful error message to the consumer.
First the traits (you may have to tweak it with your requirements):
template <typename T>
auto is_iterator_impl(T* it)
-> decltype(**it, ++(*it), (*it) == (*it), std::true_type());
template <typename T>
auto is_iterator_impl(...) -> std::false_type;
template <typename T>
using is_an_iterator = decltype(is_iterator_impl<T>(0));
Note: using std::iterator_traits<IT> may be a good alternative.
With SFINAE, you may do
template <class R>
std::enable_if_t<!is_an_iterator<R>::value, RefT<R>>
make_ref(R& res) {
return RefT<R>(&res);
}
template <class R>
std::enable_if_t<is_an_iterator<R>::value && !std::is_pointer<R>::value, RefT<R>> // you may want to change return type
make_ref(R& res) {
// Implementation for iterator
}
template <class R>
std::enable_if_t<std::is_pointer<R>::value, RefT<R>> // you may want to change return type
make_ref(R& res) {
// Implementation for iterator
}
Note: as you want to manage pointer differently, I also use std::is_pointer in addition to the custom is_an_iterator.
Note: The conditions should not have overlap, else you have conflict.
Live Demo
I used is_iterator from here: https://stackoverflow.com/a/4336298/678093
This traits struct is used with SFINAE to only enable make_ref for non-iterator types:
#include <type_traits>
template<class T>
struct is_iterator
{
static T makeT();
typedef void * twoptrs[2]; // sizeof(twoptrs) > sizeof(void *)
static twoptrs & test(...); // Common case
template<class R> static typename R::iterator_category * test(R); // Iterator
template<class R> static void * test(R *); // Pointer
static const bool value = sizeof(test(makeT())) == sizeof(void *);
};
// just to make it compile
template <typename R>
struct RefT{};
template <class R, typename std::enable_if<!is_iterator<R>::value>::type* = nullptr>
RefT<R> make_ref(R& res)
{
return RefT<R>(&res);
}
int main()
{
int* a;
make_ref(a); // fails to compile
int b;
make_ref(b); // compiles once RefT is correct
return 0;
}
An alernative solution is to use std::iterator_traits:
template <class R, typename std::enable_if<std::is_same<typename std::iterator_traits<R>::value_type, void>::value>::type* = nullptr>
RefT<R> make_ref(R& res)
{
return RefT<R>(&res);
}
This could also be done by using SFINAE with std::iterator_traits, would handle all cases that previous answers handle (pointers and types having internal iterator_category typedef) but:
no need to write your own traits (like is_iterator) to do this, or at least most of the template machinery is encapsulated in iterator_traits
could also handle potential user defined iterators that were having their own iterator_traits specialization without using the generic iterator_category typedef, not sure if this relevant/legal technique but definitely possible
This questions begs a more preparation, so I provide some bits of code first and then the exact question
Assuming I have the following type declared
template<typename T>
struct some_type
{
T t_;
};
which would be constructed with a factory function like so
typedef float numeric_type;
std::vector<std::string> construction_material;
//Push_back of strings in certain form...
std::vector<std::unique_ptr<some_type<numeric_type>> instances;
build_instances(construction_material.begin(), construction_material.end(), back_inserter(instances));
and the construction function would be something like following
template<typename input_iterator, typename output_iterator>
output_iterator build_instances(input_iterator begin, input_iterator end, output_iterator out)
{
for(input_iterator iter = begin; iter != end; ++iter)
{
//This won't work, but to illustrate some ideas...
//build_instance<std::iterator_traits<output_iterator>::value_type>(*iter)
}
//[...]
return *out;
}
template<typename T>
std::unique_ptr<some_type<T>> build_instance(std::string const& material)
{
static_assert(std::is_floating_point<T>::value == true, "The template type needs to be a floating point type.");
std::unique_ptr<some_instance<T>> instance(new some_instance<T>());
//Some processing...
return instance;
}
I know I could change the function to return some container (or perhaps even templatize the container type), like
template<typename input_iterator, typename T>
std::vector<std::unique_type<T>> build_instances(input_iterator begin, input_iterator end,
output_iterator out)
{
//Likewise code to the previous snippets...
return ...
}
The problems I haven't been able to solve are:
Would it be possible -- or impossible -- to use the back_inserter like approach? It looks like being the most flexible for the caller?
How to get a hold on the numeric_type in build_instances body (as in having it through output_iterator) so that it can be used in building the instances one-by-one?
How to ensure the caller knows to wait for the objects wrapped in std::unique_ptrs? An alternative would be just as plain pointers, but I'm not enthuasiastic about that.
There's a similar kind of question with a heading How can I make this template method more elegant? (or: less explicit template parameters required), which takes a container and transforms it to a different type of a container.
Edit
As commented to Jogojapan's comment that currently I transform the input like so
std::transform(construction_material.begin(), construction_material.end(), std::inserter(instances, instances.begin()), build_instance<numeric_type>);
but the subsequent function calls need to be supplied the numeric_type typedef too, which is somewhat cumbersome. I hope to avoid that. It looks I was mistaken, but for the purpose of education and all, would it be possible to further reduce the need to typedef the numeric type and deduce it from the iterator?
An intrusive solution is to let some_type exposes its type parameter, the same way std::unique_ptr<T, D> exposes its first parameter via element_type (which we will need later):
template<typename T>
struct some_type
{
// give it an appropriate meaningful name
using value_type = T;
value_type t_;
};
template<typename input_iterator, typename output_iterator>
output_iterator build_instances(input_iterator begin, input_iterator end, output_iterator out)
{
using pointer_type = typename std::iterator_traits<output_iterator>::value_type;
using value_type = typename pointer_type::element_type::value_type;
return std::transform(begin, end, out, build_instance<value_type>);
}
You can also non-intrusively extract the first template parameter of a template specialization:
template<typename T>
struct first;
template<template<typename...> class Template, typename First, typename... Pack>
struct first<Template<First, Pack...>>> {
using type = First;
};
template<typename T>
using First = typename first<T>::type;
The value_type alias in build_instances would instead become
using value_type = First<typename pointer_type::element_type>;
As a final remark I find it a bit odd that build_instance take a T parameter but constructs instances of some_type<T>. If it took T and constructed instances of T (where perhaps T is restricted to be a specialization of some_type.) This would have spared your problem, too.