I'm writing a template function in C++17
which accepts a functor F
as argument and I want to restrict the passed in functor to have only one constant reference argument, where T
can be any type.
for example:
template <class T> struct my_struct{
std::vector<T> collection;
template <class F> std::vector<T> func(F f){
static_assert(
// CONDITION HERE!,
"f's argument is not const reference"
);
std::vector<T> ret;
std::copy_if(
std::make_move_iterator(this->collection.begin()),
std::make_move_iterator(this->collection.end()),
std::inserter(ret, ret.end()),
f
);
return ret;
}
};
Obviously, in case f
is [](auto v){return true;}
the resulting vector returned from func
will have empty elements (because those are moved before adding to resulting container). So, I need to restrict possible input functors to [](const auto& v){}
.
I have tried something like this:
static_assert(
std::is_invocable_v<F, const T&>,
"f's argument is not const reference"
);
But then func([](auto v){})
does not trigger the assertion, because T
is copyable in my case.
The func([](auto& v){})
also passes the test, because auto
can be const T
.
But I need to limit possible lambdas to be func([](const auto& v){})
.
I finally managed to achieve it in the following way:
template <class T> struct my_struct{
std::vector<T> collection;
struct noncopyable_value_type : T{
noncopyable_value_type(const noncopyable_value_type&) = delete;
noncopyable_value_type& operator=(const noncopyable_value_type&) = delete;
};
template <class F> std::vector<T> func(F f){
static_assert(
std::is_invocable_v<F, noncopyable_value_type>,
"f's argument must be const reference"
);
std::vector<T> ret;
std::copy_if(
std::make_move_iterator(this->collection.begin()),
std::make_move_iterator(this->collection.end()),
std::inserter(ret, ret.end()),
f
);
return ret;
}
};
But still, the problem here is that it only works with generic lambdas.