How to deal with template const and non-const parameters? - c++

I have a Template function taking in const types such as:
template <class T, class U>
void process(const T& v1, const U& v2)
{
//do some things
verify(v1);
verify(v2);
}
Then the verify function checks the Type for T using if constexpr as follows:
(The function also returns the variable. I set it to auto for the purpose of this question)
template <class T>
auto verify(const T& t)
{
if constexpr (is_same_v<T, int>)
return t;
if constexpr (is_same_v<T, string>)
return t;
if constexpr (is_same_v<T, double*>)
return t;
else
static_assert(false, "Type not allowed");
}
if the type is not found it will trigger a compilation error.
This all works very fine but the problem is I would like to make v2 a non-const U& parameter. This triggers the static_assert and I don't know why. I also set all parameters in both functions to non-const but I still get the same error. All I really want is to pass the arguments by reference. Can anyone give me some hints? Thanks in advance.

This is one of those things you'd need to know.
The form you're looking for is
template <class T> auto verify(T&& t) {
The reason is that T can be const U, a const-qualified type. The double && is necessary for rvalue references.
You probably want std::is_same_v<std::remove_cv_t<T>>, ...
And to simply things:
template <class T> auto verify(T&& t)
{
using baseT = std::remove_cv_t<T>;
static_assert(is_same_v<baseT, int> ||
is_same_v<baseT, string> ||
is_same_v<baseT, double*>);
return t;
}

A better way of doing that would be to static_assert some type trait:
#include <string>
#include <type_traits>
template <class T, class... Y>
inline bool constexpr is_one_of =
(std::is_same_v<std::decay_t<T>, std::decay_t<Y>> || ...);
template <class T>
void verify() {
static_assert(is_one_of<T, int, std::string, double*>);
}
template <class T, class U>
void process(T const& v1, U const& v2) {
verify<T>();
verify<U>();
// ...
}

Related

Passing template parameter pack to type_traits and std::enable_if

I am trying to create a class holding std::variant with a member function that would only accept types held by the nested variant object.
That function works basically the same way as variant's operator=. However, the question is - how do I use std::enable_if and type_traits together with template parameter pack?
The example below (attempting to check if any of the Types is contractible from T) obviously doesn't compile:
template<typename... Types>
class Wrapper
{
public:
template<typename T, std::enable_if_t<std::is_constructible_v<Types..., T>, bool> = true>
void Set(const T& data) {
m_data = data;
}
private:
std::variant<Types...> m_data;
};
int main()
{
Wrapper<int, float> wrapper;
wrapper.Set(123);
return 0;
}
How do I use std::enable_if and type_traits together with template parameter pack?
You might do as follows:
#include <type_traits>
template<typename T, typename... Types>
inline constexpr bool areAllowedTypes = (std::is_constructible_v<T, Types> && ...);
// && -> if all the types must be convertable, otherwise use ||
now
template<typename T>
auto Set(const T& data) ->std::enable_if_t<areAllowedTypes<T, Types...>>
{
m_data = data;
}
Or since you have c++17 compiler support, using if constexpr
template<typename T>
void Set(const T& data)
{
if constexpr (areAllowedTypes<T, Types...>) m_data = data;
}

Expression SFINAE: how to select template version based on whether type contains a function with one or more arguments

I'm trying to select at compile time between different template implementations depending on whether or not the argument implements a particular function. This is a common question (see this S.O. question and this example referenced by this article. The common answer is "use expression SFINAE".
Most of the examples show how expression SFINAE can be used to select based on the presence of a zero-argument function. I've tried to adapt these to my 1-argument use case by using declval (loosely based off of this example), but I cannot seem to get it to work.
I'm sure I'm doing something wrong in the example below, but I can't figure out what it is. The example is trying to define two versions of a template bool Util::Container::Contains(container, value) which will use the container's built-in find(value) method if it exists, and otherwise fall back to a linear search using std::find(...)
Please note: I know I can make this work by just overloading Contains() for unordered_map, unordered_set, etc., but instead I'd like to figure out this pattern-based approach so that it will automatically delegate to any container's find(value) without requiring an overload to be added.
#include <unordered_set>
#include <unordered_map>
#include <vector>
#include <string>
namespace Util::Container {
namespace Detail
{
template <typename T>
class HasFindMethod
{
private:
typedef char YesType[1];
typedef char NoType[2];
// This is how the examples show it being done for a 0-arg function
//template <typename C> static YesType& Test(decltype(&C::find));
// Here's my attempt to make it match a 1-arg function
template <typename C> static YesType&
Test(decltype(std::declval<C>().find(std::declval<const C::value_type&>())));
template <typename C> static NoType& Test(...);
public:
enum { value = sizeof(Test<T>(0)) == sizeof(YesType) };
};
}
// Fallback: uses std::find() to do the lookup if no type-specific T::find(value) exists
template<typename T>
bool Contains(const T& in_container, const typename T::value_type& in_item)
{
const auto& result = std::find(in_container.cbegin(), in_container.cend(), in_item);
return (result != in_container.cend());
}
// Preferred: use T::find() to do the lookup if possible
template<typename T>
inline typename std::enable_if<Detail::HasFindMethod<T>::value, bool>::type
Contains(const T& in_container, const typename T::value_type& in_item)
{
return (in_container.find(in_item) != in_container.end());
}
}
int main()
{
const std::vector<int> v { 1, 2, 3 };
const std::unordered_map<int, std::string> m { {1,"1" }, {2,"2"} };
const std::unordered_set<std::string> s { "1" , "2" };
// These should use the std::find()-based version of Contains() since vector and unordered_map
// have no find(value_type) method. And they do.
const bool r_v = Util::Container::Contains(v, 2);
const bool r_m = Util::Container::Contains(m, { 2, "2" });
// !!!!!!
//
// This should use the T::find(value_type)-based version of Contains() since
// unordered_set has a find(value_type) method.
//
// But it doesn't --- that's the issue I'm trying to solve.
//
const bool r_s = Util::Container::Contains(s, "2");
}
If anyone can show me how to fix this, I'd very much appreciate it.
FWIW, I'm attempting to implement this in Visual Studio 2017 v15.8
An easy way with decltype is
template<typename C, typename V>
auto Contains(const C& c, const V& value)
-> decltype(std::find(c.cbegin(), c.cend(), value) != c.cend())
{
return std::find(c.cbegin(), c.cend(), value) != c.cend();
}
template <typename C, typename Key>
auto Contains(const C& c, const Key& key)
-> decltype(c.find(key) != c.end())
{
return c.find(key) != c.end();
}
but then when both function are possible you would have ambiguous call.
So just add extra parameter to prioritize the overload:
struct low_priority {};
struct high_priority : low_priority {};
template<typename C, typename V>
auto ContainsImpl(low_priority, const C& c, const V& value)
-> decltype(std::find(c.cbegin(), c.cend(), value) != c.cend())
{
return std::find(c.cbegin(), c.cend(), value) != c.cend();
}
template <typename C, typename Key>
auto ContainsImpl(high_priority, const C& c, const Key& key)
-> decltype(c.find(key) != c.end())
{
return c.find(key) != c.end();
}
template <typename C, typename T>
auto Contains(const C& c, const T& t)
-> decltype(ContainsImpl(high_priority{}, c, t))
{
return ContainsImpl(high_priority{}, c, t);
}
Now about your version, you have several issues
The last one:
// Expected Fallback: uses std::find() to do the lookup if no type-specific T::find(value) exists
template<typename T>
bool Contains(const T&, const typename T::value_type&);
// Expected Preferred: use T::find() to do the lookup if possible
template<typename T>
typename std::enable_if<Detail::HasFindMethod<T>::value, bool>::type
Contains(const T&, const typename T::value_type&);
SFINAE allows to discard overload, but not to prioritize them.
You have to use priority, as shown above, or create exclusive set of overload:
template<typename T>
typename std::enable_if<!Detail::HasFindMethod<T>::value, bool>::type
Contains(const T&, const typename T::value_type&);
template<typename T>
typename std::enable_if<Detail::HasFindMethod<T>::value, bool>::type
Contains(const T&, const typename T::value_type&);
In addition to that, as mentioned in comment map family would use key_type and not value_type.
Then your detection code is buggy,
// This is how the examples show it being done for a 0-arg function
//template static YesType& Test(decltype(&C::find));
No, this detects if C has a method find (without overload).
template <typename C> static YesType&
Test(decltype(std::declval<C>().find(std::declval<const C::value_type&>())));
Here, you use SFINAE, but final type would be the (const_)iterator, and Test<C>(0) won't take that overload (unless iterator can be build from 0 which is not the regular case). Adding extra * is a possibility, then you have pointer on iterator which might be initialized by 0.
Else you might use code provided in your provided link:
namespace detail{
template<class T, typename ... Args>
static auto test_find(int)
-> sfinae_true<decltype(std::declval<T>().find(std::declval<const Arg&>()...))>;
template<class, class ...>
static auto test_find(long) -> std::false_type;
} // detail::
template<class C, typename ... Args>
struct has_find : decltype(detail::test_find<T, Args...>(0)){};
// int has higher priority than long for overload resolution
and then use your traits with std::enable_if has_find<Container, Key>::value.
The immediate problem is that the argument you are passing to Test is not compatible with the YesType version.
For example, Detail::HasFindMethod<std::unordered_set<int>> will result in the following two Test signatures (because find would return an iterator):
static YesType& Test(std::unordered_set<int>::iterator);
static NoType& Test(...);
You try to call Test with the argument 0, which is not convertible to iterator. Hence, the second one is picked.
As a solution, use a pointer:
template <typename C> static YesType&
Test(decltype(std::declval<C>().find(std::declval<const C::value_type&>()))*);
// ^
Then do the check with a nullptr argument:
enum { value = sizeof(Test<T>(nullptr)) == sizeof(YesType) };
Now we would have ambiguity (the Test(...) would also match), so we can make that one a worse match:
template <typename C, class ... Args> static NoType& Test(void*, Args...);
As shown in the other answers, this is still a comparatively convoluted solution (and there are more issues that prevent it from working in your instance, such as ambiguity between the overloads when the enable_if does work). Just explaining the particular stopper in your attempt here.
A simpler (in my opinion) and more readable solution can be achieved using void_t utility:
template <typename T, typename Dummy = void>
struct has_member_find : std::false_type { };
template <typename T>
struct has_member_find<T,
std::void_t<decltype(std::declval<T>().find(std::declval<typename T::value_type &>()))>>
: std::true_type { };
template<typename T>
std::enable_if_t<!has_member_find<T>::value, bool>
Contains(const T& in_container, const typename T::value_type& in_item)
{
const auto& result = std::find(in_container.cbegin(), in_container.cend(), in_item);
return (result != in_container.cend());
}
template<typename T>
std::enable_if_t<has_member_find<T>::value, bool>
Contains(const T& in_container, const typename T::value_type& in_item)
{
return (in_container.find(in_item) != in_container.end());
}
Note that void_t is only available since C++17, however it you don't have a full C++17 support you can define it yourself since it's definition is ridiculously simple:
template< class... >
using void_t = void;
You can learn more about this utility and the pattern it introduces in this paper.

function parameter pack for member variable pointer

I am trying to access variables in a struct thru nested member pointers:
#include <iostream>
typedef struct {
int a;
int b;
} bar;
typedef struct {
int c;
bar d;
} baz;
template <typename obj, class C1, class C2, typename T1, typename T2>
T2 test1(const obj& obj_, T1 C1::* field1_, T2 C2::* field2_)
{
return (obj_.*field1_).*field2_;
}
int main()
{
baz myObj;
test1(myObj, &baz::d, &bar::b);
}
How would I turn the function test into a variadic function, so that i can access variables at variable "depths" into the struct?
I've tried to follow the second example in the Function parameter list section here, but am not getting it it seems:
template <typename obj, class ...C, typename... T>
void test2(const obj& obj_, T C...::* field_)
{
// ??
// and what about the function return parameter?
}
int main()
{
baz myObj;
test2(obj,&baz::d,&bar::b);
test2(obj,&baz::c);
}
With this, the definition of test2() already doesn't compile.
Any (latest) version of C++ can be used (with MSVC though).
For tests purpose, here is a complete program on coliru.
Solution
Thanks to Silvio's answer, I was able to solve it. Taking advantage of C++17, it can be made slightly shorter still:
template <typename T, typename S, typename... Ss>
auto inline test2(const T& obj, S field1, Ss... fields)
{
if constexpr (!sizeof...(fields))
return obj.*field1;
else
return test2(obj.*field1, fields...);
}
There may be a cleaner way to do this, but you can certainly take the "throw it at the wall and see what sticks" approach that C++ templates love so much.
template <typename T>
auto test2(const T& obj) -> T {
return obj;
}
template <typename T, typename S, typename... Ss>
auto test2(const T& obj, S field1, Ss... fields)
-> decltype(test2(obj.*field1, fields...)) {
return test2(obj.*field1, fields...);
}
The base case is pretty straightforward. If we don't pass any fields, we just return the original object itself. The recursive case is just that: we recurse. The return type is declared to be... the declared type of the return value. The argument types are simply variables. They'll be instantiated fully as needed. If you pass arguments that don't make sense or don't type check, you'll get some wonderfully ugly error messages.
This requires c++17 support for folding expressions.
namespace utils {
template<class T>struct tag_t{ using type=T; };
template<class...Ts>
using last = typename std::tuple_element_t< sizeof...(Ts)-1, std::tuple<tag_t<Ts>...> >::type;
template<class Lhs, class F>
struct fold_invoker_t;
template<class Lhs, class F>
fold_invoker_t<Lhs, F> fold_invoker(Lhs&&lhs, F&& f);
template<class Lhs, class F>
struct fold_invoker_t {
Lhs lhs;
F f;
template<class Rhs>
auto operator*( Rhs&& rhs )&& {
return fold_invoker(std::forward<F>(f)(std::forward<Lhs>(lhs), std::forward<Rhs>(rhs)), static_cast<F>(f));
}
};
template<class Lhs, class F>
fold_invoker_t<Lhs, F> fold_invoker(Lhs&&lhs, F&& f){ return {std::forward<Lhs>(lhs), std::forward<F>(f)}; }
}
then we write:
template <typename Obj, class ...C, typename... T>
utils::last<Obj, T...> const& test2(const Obj& obj, T C::*... field)
{
auto get_member=[](auto&& elem, auto&& memptr)->decltype(auto){ return elem.*memptr; };
return (utils::fold_invoker( obj, get_member ) * ... * field).lhs;
}
and it is all expanded on that one line.
live example.
No idea if this will work in MSVC's C++17 support.

C++ template template non-type parameter

I am trying to achieve the following:
template<template<typename> bool Function_, typename ... Types_>
constexpr auto find(Tuple<Types_ ... >) noexcept
{
// ...
}
where a possible function could be:
template<typename T>
inline constexpr bool is_pointer_v = is_pointer<T>::value;
so then the usage of find would be:
Tuple<int, char, void *> t;
find<is_pointer_v>(t);
don't worry about the implementation of find, I am just asking about how to do "template < typename > bool Function_" as the bool part is invalid in c++ currently.
any help is appreciated!
EDIT:
here is an example of why I can't pass the "is_pointer" to the function:
template<typename T_>
constexpr auto add_pointer(Type<T_>) noexcept
{ return type_c<T_ *>; }
template<typename F_, typename T_>
constexpr auto apply(F_ f, Type<T_> t) noexcept
{
return f(t);
}
int main(void)
{
Type<int> t_i;
apply(add_pointer, t_i);
}
this produces the compiler error:
error: no matching function for call to ‘apply(< unresolved overloaded function type >, sigma::meta::Type&)’
apply(add_pointer, t_i);
any help is appreciated!
You can simply wrap your functions within functors.
As a minimal, working example:
template<typename>
struct Type {};
template<typename>
struct type_c {};
template<typename T_>
struct add_pointer {
static constexpr auto invoke(Type<T_>) noexcept
{ return type_c<T_ *>{}; }
};
template<template<typename> class F_, typename T_>
constexpr auto apply(Type<T_> t) noexcept {
return F_<T_>::invoke(t);
}
int main(void) {
Type<int> t_i;
apply<add_pointer>(t_i);
}
If you can't change them directly, create functors that forward everything to the right function through a static constexpr member method.
I am just asking about how to do "template < typename > bool Function_" as the bool part is invalid in c++ currently.
As far I know, template-template arguments are a completely different thing. They are intended for containers, not for functions. So class, not bool.
here is an example of why I can't pass the "is_pointer" to the function
Your example doesn't work because add_pointer is a template function, so when you call
apply(add_pointer, t_i);
the compiler doesn't know which version (which type T) of add_pointer to use.
A solution can be explicit it, as in the following simplified example
#include <tuple>
#include <iostream>
template <typename T>
constexpr auto add_pointer(std::tuple<T>) noexcept
{ std::cout << "add_pointer" << std::endl; return 0; }
template <typename F, typename T>
constexpr auto apply(F f, std::tuple<T> t) noexcept
{ return f(t); }
int main(void)
{
std::tuple<int> t_i { 1 };
apply<int(*)(std::tuple<int>)>(add_pointer, t_i);
}
but I understand that explicating int(*)(std::tuple<int>) is a big pain in the ass.
You can simplify a little using the fact that you pass t so you can deduce the type of the argument received by the function, but (for a generic solution) I don't know how to avoid to explicit the return type of the function (maybe it's possible, but (in this moment) I don't know.
So you can simplify the call as follows
apply<int>(add_pointer, t_i);
and the following is a little more general example
#include <tuple>
#include <iostream>
template <typename ... Ts>
constexpr auto add_pointer(std::tuple<Ts...> const &) noexcept
{ std::cout << "add_pointer" << std::endl; return 0; }
template <typename R, typename ... Ts,
typename F = R(*)(std::tuple<Ts...> const &)>
constexpr auto apply(F f, std::tuple<Ts...> t) noexcept
{ return f(t); }
int main(void)
{
std::tuple<int> t_i { 1 };
apply<int>(add_pointer, t_i);
}

Template deduction fails for known argument

Consider following code
template<typename T>
T modify(const T& item, std::function<T(const T&)> fn)
{
return fn(item);
}
When trying to use it as modify(5, [](const int& i){return 10*i;}); it fails to compile with
could not deduce template argument for 'std::function<T(const T &)> from lambda
I know that compiler can not deduce T from lambda, because lambda is not std::function, but isn't T already deduced from 5?
I can get over it using
template<typename T, typename F>
T modify(const T& item, const F& functor)
{
return functor(item);
}
for which previous example compiles, but it is in my opinion less intuitive. Is there a way to let the function argument to remain std::function and have it's template argument deduced automatically from item?
What you basically want to do is prevent deduction from happening. If template deduction occurs, it will fail (because a lambda is not a std::function<> - it doesn't matter that T was deduced from the first argument, deduction must succeed in every argument that is a deduced context). The way to prevent deduction is to stick the entire argument in a non-deduced context, the easiest way of doing that is to throw the type into a nested-name-specifier. We create such a type wrapper:
template <class T> struct non_deduce { using type = T; };
template <class T> using non_deduce_t = typename non_deduce<T>::type;
And then wrap the type in it:
template<typename T>
void foo(const T& item, std::function<void(T)> f);
template<typename T>
void bar(const T& item, non_deduce_t<std::function<void(T)>> f);
foo(4, [](int ){} ); // error
bar(4, [](int ){} ); // ok, we deduce T from item as int,
// which makes f of type std::function<void(int)>
Note, however, that:
template <typename T, typename F>
void quux(const T&, F );
is not really any less readable, and strictly more performant.
You can do it by using the identity trick as below:
template <typename T>
struct identity {
typedef T type;
};
template<typename T>
T modify(const T& item, typename identity<std::function<T(const T&)>>::type fn) {
return fn(item);
}
Live Demo