I'd like to manipulate some data with certain types in a template argument list.
In my case, I would like to check if some of the elements are some kind of an Iterable, and if there are any, then I want to use std::advance on them.
This is what I had in mind: (well it obviously will not compile but gives you the right idea what I want to achieve here)
#include <typeinfo>
#include <thread>
template<class _Func, class Iterator, class... _Args>
void
start(_Func pFunc, const Iterator begin, const Iterator end, _Args&&... args)
{
Iterator pt = begin;
Iterator ptNext = begin;
for (unsigned int i = 0; i < this->nThreads(); i++)
{
std::advance(ptNext, partialSize);
this->getThreads(i) = std::thread(pFunc, pt, ptNext, std::forward<_Args>(args)...);
pt = ptNext;
[](...){}((typeid(args) == typeid(Iterator) ? std::advance(args, partialSize) : false)...);
}
}
I think the problem's (maybe?) that, that the argument list gets expanded at compile time and then it will see, that I want to use std::advance on something, that may not even be an Iterable type.
In the code above begin and end are iterators of a data sequence and the partialSize variable tells, that a thread should process only a part of the sequence.
So the goal is, if any other Iterable types are passed through the argument list, say: std::vector<>::iterator or std::list<>::iterator or even a double*, then I would like to std::advance them.
Are there any solutions for this problem? Can I achieve something like this?
I've implemented a function that advances all iterators passed to it. It simply ignores arguments of any other type.
The code requires C++17, but can be ported to earlier versions of standard.
#include <iterator>
#include <type_traits>
template <class T, class = void>
struct is_iterator : std::false_type {};
template <class T>
struct is_iterator<T, std::void_t<typename std::iterator_traits<T>::iterator_category>> : std::true_type {};
template <class Distance, class T>
void advance_if_iterable_impl(Distance n, T& t)
{
if constexpr (is_iterator<T>::value)
std::advance(t, n);
}
template <class Distance, class... Args>
void advance_if_iterable(Distance n, Args&... args)
{
(advance_if_iterable_impl(n, args), ...);
}
#include <iostream>
int main()
{
int i = 42;
const char* str = "Hello World!\n";
advance_if_iterable(2, i, str);
// `int` isn't an iterator, it stays the same
std::cout << i << '\n';
// `const char*` is a random iterator, so it was advanced by two
std::cout << str;
return 0;
}
Related
I want to write a class that takes a pair of iterators as parameters to the constructor, but I dont know how to raise an error at compile-time when those iterators' value_type doesn't match an expected type. This is what I tried using typeid:
#include <vector>
struct foo {
std::vector<double> data;
template <typename IT>
foo(IT begin, IT end){
typedef int static_assert_valuetype_is_double[
typeid(typename IT::value_type) == typeid(double) ? 1 : -1
];
std::cout << "constructor called \n";
data = std::vector<double>(begin,end);
}
};
int main()
{
std::vector<double> x(5);
foo f(x.begin(),x.end()); // double: ok
std::vector<int> y(10);
foo g(y.begin(),y.end()); // int: should not compile
}
Note that in this case, int to double would be fine, but thats just an example and in the real code the types have to match exactly. To my surprise in both cases, the constructor works without errors (there is only a warning about the unused typedef). Does the -1 sized array static assert trick not work when the typedef is declared inside a method? How do I produce an error when IT::value_type is the wrong type?
PS: would be nice if there was an easy C++98 solution, but if this gets too complicated, I could also accept a C++11 solution.
In modern C++, you could have used std::is_same and static_assert:
static_assert(std::is_same_v<typename std::iterator_traits<IT>::value_type, double>,
"wrong iterator");
See also std::iterator_traits: an iterator it is not guaranteed to have a value_type typedef, and one should use std::iterator_traits<it>::value_type instead.
In C++ 98, is_same is trivial to implement, static_assert needs a negative-size array trick or the BOOST_STATIC_ASSERT.
For a solution that works in C++98 and later.....
#include <iterator>
template<class T> struct TypeChecker
{};
template<> struct TypeChecker<double>
{
typedef double valid_type;
};
template <typename IT>
void foo(IT begin, IT end)
{
typename TypeChecker<typename std::iterator_traits<IT>::value_type>::valid_type type_checker;
(void)type_checker;
// whatever
}
Instantiations of foo() will succeed for any for an iterator for which value_type is double, and fail to compile otherwise.
The premise is that TypeChecker<x> does not have a valid_type for any x other than double, but we attempt to instantiate an instance of that type in foo(). The (void)type_checker prevents warnings, from some compilers about a variable that is never used, for valid types.
Here is a C++98 compliant way to implement it.....
First the fun part: Implementing a is_same is rather straightforward
template <typename T,typename U> struct is_same_type { static const bool value; };
template <typename T,typename U> const bool is_same_type<T,U>::value = false;
template <typename T> struct is_same_type<T,T> { static const bool value; };
template <typename T> const bool is_same_type<T,T>::value = true;
Now the not-so-fun part (C++11 really helps to statically assert without causing coworkers raising some eyebrows):
struct foo {
std::vector<double> data;
template <typename IT>
foo(IT begin, IT end) : data(begin,end) {
typedef int static_assert_valuetype_is_double[
is_same_type<double,typename IT::value_type>::value ? 1 : -1
];
std::cout << "constructor called \n";
}
};
int main(){
std::vector<double> x(5,2.3);
foo f(x.begin(),x.end());
for (std::vector<double>::iterator it = f.data.begin(); it != f.data.end();++it) std::cout << *it << " ";
//std::vector<int> y(10,3);
//foo g(y.begin(),y.end()); // THIS FAILS (AS EXPECTED)
}
As pointed out by others, I should actually be using std::iterator_traits<IT>::value_type as not every iterator has a value_type. However, in my case I rather want to restrict the possible iterators to a small set and disallowing iterators without a value_type isnt a problem in my specific case.
Also note that the code in the question assigned to the member, while it is of course better to use the initializer list.
I am getting an error when using template type deduction combined with C++14 std::get<> with type indices. The code might look a little complex, but I've tried to whittle it down to the bare basics of what's going on. It's really just an Observer pattern... The struct 'A' allows observers to be set based on message type (M1, M2, ...). Note that there is only one observer per message type, in order to keep things simple.
Now the trick (and the part that is failing) is using C++14's std::get<>, which allows you to index into a tuple of unique types using the actual type. Here is a simple example demonstrating what I mean:
void sample()
{
std::tuple<int, float> myTuple;
std::get<float>(myTuple) = 3.141f; // C++14 allows this
std::get<1>(myTuple) = 3.141f; // C++11 way to do it, using index
}
With this in mind, here is my program (separate from the above code) that does NOT compile because the C++14 tuple type indexing is failing on an inferred type:
#include <cxxabi.h>
#include <stdlib.h>
#include <functional>
#include <vector>
#include <tuple>
#include <typeinfo>
#include <iostream>
#include <string>
// ===================================
// A quick'n'dirty way to print types (nonportable)
// And yes, I know this code could be improved :)
inline
std::string demangle(char const *mangled)
{
char *output = (char *)malloc(16384);
size_t length = 16384;
int status;
__cxxabiv1::__cxa_demangle(mangled, output, &length, &status);
std::string s(output, length);
free(output);
return s;
}
#define DEMANGLE(T) demangle(typeid(T).name())
// ===================================
struct A
{
struct M1
{};
struct M2
{};
using Tuple = std::tuple<
std::function<void(M1 const &)>
,std::function<void(M2 const &)>
>;
template<typename T>
void setObserver(T func)
{
// This works fine
std::cout << DEMANGLE(T) << std::endl;
// ************************************************
// The line below does not compile (std::get fails)
//
// Note the type of T prints out as:
// std::_Bind<std::_Mem_fn<void (B::*)(A::M1 const&)> (B*, std::_Placeholder<1>)>
//
// Rather than the (desired):
// std::function<void (A::M1 const&)>(A::M1 const&)> (B*, std::_Placeholder<1>)>
//
// ************************************************
std::get<T>(tuple_) = func; // C++14 only
}
private:
Tuple tuple_;
};
// ===================================
struct B
{
void func(A::M1 const &)
{}
};
// ===================================
int main()
{
A *a = new A;
B *b = new B;
using namespace std::placeholders;
a->addObserver(std::bind(&B::func, b, _1));
return 0;
}
UPDATE:
The proposed solution does solve the problem of converting from std::bind(...) to std::function(...), BUT it requires me to have a separate setObserver() function for each of my types M1, M2, ...
How can I templatize setObserver() to fix this?
std::bind()does not return std::functionbut some unspecified type convertible to std::function<>. Secondly, std::get<>() in C++14 form requires exact type, not just anything convertible to one of tuples member types.
To achieve what you want - you need to convert your T to one of your tuple types.
E.g. you might move your current setObserver to private section and rename it - and create functions for your desired types:
template<typename T>
auto setObserver(T func)
-> typename std::enable_if<std::is_convertible<T, std::function<void(M1 const &)>>::value>::type
{
this->template setObserverImpl<std::function<void(M1 const &)>>(func);
}
template<typename T>
auto setObserver(T func)
-> typename std::enable_if<std::is_convertible<T, std::function<void(M2 const &)>>::value>::type
{
this->template setObserverImpl<std::function<void(M2 const &)>>(func);
}
private:
template<typename T>
void setObserverImpl(T func)
{
// no change here
}
You need to make the current setObserver to be template function unless you have just two types.
To template this solution - either use variant functions for each Mx type where "non convertible version" will be empty:
template <typename T, typename M>
auto setObserverTemplate(T func) -> typename std::enable_if<std::is_convertible<T, std::function<void(M const &)>>::value>::type
{
this->template setObserverImpl<std::function<void(M const &)>>(func);
}
template <typename T, typename M>
auto setObserverTemplate(T) -> typename std::enable_if<not std::is_convertible<T, std::function<void(M const &)>>::value>::type
{
// do nothing
}
template<typename T>
auto setObserver(T func)
{
this->template setObserverTemplate<T,M1>(func);
this->template setObserverTemplate<T,M2>(func);
}
Or, probably much better - variadic version with sentinel empty function:
template<typename T, typename MFirst, typename ...M>
auto setObserverVariadic(T func)
{
this->template setObserverTemplate<T,MFirst>(func);
this->template setObserverVariadic<T,M...>(func);
}
template<typename T>
auto setObserverVariadic(T)
{
}
template<typename T>
auto setObserver(T func)
{
this->template setObserverVariadic<T,M1,M2>(func);
}
Last comment - you might try to "retrieve" current types (I mean these list of Mx types) from your tuple type. How to do it - that could be good candidate for new question.
I'm trying to make a method that picks a random element from a container type, like std::vector. Before, I was using this:
std::string pick_random(std::vector<std::string> c) {
int r = std::rand() % ids.size() + 1;
auto it = c.begin();
std::advance(it, r);
return *it;
}
which, as far as I could tell, worked fine. That's not to say it is fine, just that it appeared to be.
I soon had to do the same thing for another container, so I tried using template template arguments to make the method generic:
template <template<typename element_t> container_t>
element_t pick_random(container_t from) { /* ... */ }
This, however, throws an error:
element_t does not name a type
I think my intent is clear enough, but to restate it: I'm trying to get the element type of the list. I could have a separate template parameter, but then it can't properly infer the type. I've tried various different versions, but none work.
container_t is not a type, container_t<T> is.
You may use the following:
template <template<typename, typename...> C, typename T, typename...Ts>
T pick_random(const C<T, Ts...>& from);
as for std::vector, you have allocator: std::vector<T, Alloc>.
In C++14, you may simply use auto
template <typename C>
auto pick_random(const C& from) { /* ... */ }
I don't think that "template template arguments" are required here,
you could simply use the value_type from the container:
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <list>
template <typename T>
typename T::value_type pick_random(T& from) {
int r = std::rand() % from.size();
auto it = from.begin();
std::advance(it, r);
return *it;
}
int main() {
std::srand(std::time(0));
std::vector<std::string> words {"the", "frogurt", "is", "also", "cursed"};
std::list<int> numbers {1, 2, 3, 4, 5};
std::cout << "words: " << pick_random(words) << std::endl;
std::cout << "numbers: " << pick_random(numbers) << std::endl;
}
value_type - the type of the values that can be obtained by dereferencing the iterator.
Source: http://en.cppreference.com/w/cpp/iterator/iterator_traits
Even better would be to avoid the arbitrary restriction on class templates. After all, why not be able to pick an element from a raw array? In order to correctly name the type in C++11, we'd have to get the result of an unqualified call to begin, which we can get via:
namespace detail {
using std::begin;
template <typename C>
auto adl_begin(C&& c) -> decltype(begin(std::forward<C>(c))) {
return begin(std::forward<C>(c));
}
}
using detail::adl_begin;
And then use that to deduce the element_type from an arbitrary container:
template <typename C>
auto pick_random(C& container) -> decltype(*adl_begin(container))
{ /* rest as before */ }
Side-note: take your container by reference, not by value.
If you're only using standard library containers then you can get the stored type out of them by using container_t::value_type.
template <typename container_t>
typename container_t::value_type pick_random(container_t& container)
{ ... }
Below is a flawed (and simplified) template function that expects to work on a template arg that can be converted to one of a predefined number of types.
It happens to be 2 types, but it cold be many more.
void do_something_type_specific( const int &unused ) { std::cout << 'i'; }
void do_something_type_specific( const std::string &unused ) { std::cout << 's'; }
template< typename Iterator >
void perform_work_on_a_range( Iterator begin, Iterator end )
{
do_something_type_specific( *begin );
// Perhaps more code...
}
This happens to produce the desired results in my environment.
Template instances will compile successfully iff *Iterator produces a type that's convertible to exactly one of the choices.
However, this code unnecessarily requests that the conversion be performed and, despite unused being unused, there is still UB when begin == end.
How can this this behavior be implemented in C++03 without these problems?
Instead of dereferencing the iterator that my result in undefined behaviour when begin == end, you could try using std::iterator_traits<>. E.g.:
#include <iterator>
#include <string>
#include <cstdio>
void do_something_type_specific(std::string const&) { printf("%s\n", __PRETTY_FUNCTION__); }
void do_something_type_specific(int const&) { printf("%s\n", __PRETTY_FUNCTION__); }
template<class T>
struct ProduceValue
{
static T value;
};
template<class T>
T ProduceValue<T>::value;
// Specializations for types that can't be default constructed or must be initialized.
template<>
char* ProduceValue<char*>::value = "";
template< typename Iterator >
void perform_work_on_a_range( Iterator begin, Iterator end )
{
typedef typename std::iterator_traits<Iterator>::value_type value_type;
do_something_type_specific(ProduceValue<value_type>::value);
}
int main() {
char** p = 0;
perform_work_on_a_range(p, p);
long* q = 0;
perform_work_on_a_range(q, q);
}
Output:
void do_something_type_specific(const string&)
void do_something_type_specific(const int&)
The only inconvenience is that ProduceValue<T> has to be specialized for types that can't be default constructed or must be initialized for other reasons (like char*).
There is a boost::is_convertible metafunction that you can use to determine if a type T can be converted to some other type U.
Secondly, for begin == end, just insert a run-time check.
The problematic code in the question is trying to leverage features of both template parameters and function parameters.
Function parameters allow type conversions, but require an instantiation of the type. Template parameters don't need instantiation, but also don't perform type conversions.
The pattern below uses Boost's enable_if and is_convertible to allow template functions to be chosen by the compiler as if template parameters supported the same type conversion rules as function parameters. (Thank #dhavenith for the suggestion)
#include <boost/utility.hpp>
#include <boost/type_traits.hpp>
// enable_if_c makes the return type either void or a Substitution Failure.
template < typename T>
typename boost::enable_if_c<boost::is_convertible<T,int>::value>::type
do_something_type_specific()
{
std::cout << 'i';
}
template < typename T>
typename boost::enable_if_c<boost::is_convertible<T,std::string>::value>::type
do_something_type_specific()
{
std::cout << 's';
}
template< typename Iterator >
void perform_work_on_a_range( Iterator begin, Iterator end )
{
// This code is from #MaximYegorushkin's answer. Vote him up :)
typedef typename std::iterator_traits<Iterator>::value_type value_type;
do_something_type_specific<value_type>();
// Perhaps more code...
}
This has been verified with #MaximYegorushkin's sample main.
int main() {
char** p = 0;
perform_work_on_a_range(p, p);
long* q = 0;
perform_work_on_a_range(q, q);
}
Output:
si
You probably want to do something like this instead:
template <typename T>
void do_something_type_specific() {}
template <>
void do_something_type_specific<int>() {...}
template <typename Iterator>
void perform_work_on_a_range(Iterator begin, Iterator end) {
do_something_type_specific<typename Iterator::value_type>();
}
I have a
typedef std::tuple<A, B> TupleType;
and would like to use the list of classes
for a "template".
Suppose I have:
template<typename... args>
std::tuple<args...> parse(std::istream &stream) {
return std::make_tuple(args(stream)...);
}
and that I can successfully use it with:
auto my_tuple = parse<A, B>(ifs);
is it possible to avoid having to specify the class list A,B if I already have a
typedef std::tuple<A,B> TupleType;
where the list A,B is already present?
an example:
#include <cstdlib> // EXIT_SUCCESS, EXIT_FAILURE
#include <iostream> // std::cerr
#include <fstream> // std::ifstream
#include <tuple> // std::tuple
class A {
public:
A(std::istream &); // May throw FooBaarException
};
class B {
public:
B(std::istream &); // May throw FooBaarException
};
template<typename... args>
std::tuple<args...> parse(std::istream &stream) {
return std::make_tuple(args(stream)...);
}
int main() {
std::ifstream ifs;
ifs.exceptions(ifstream::eofbit | ifstream::failbit | ifstream::badbit);
int res = EXIT_FAILURE;
try {
ifs.open("/some/file/path", std::ios::in | std::ios::binary);
auto my_tuple = parse<A, B>(ifs); // my_tuple is of the type std::tuple<A,B>
/* Here do something interesting with my_tuple */
res = EXIT_SUCCESS;
} catch (ifstream::failure e) {
std::cerr << "error: opening or reading file failed\n";
} catch (FooBaarException e) {
std::cerr << "error: parsing in a constructor failed\n";
}
return res;
}
The underlying problem in your situation seems to be that you'd like to specialize the function template parse for the special case when the template argument is a std::tuple. Unfortunately, this kind of specialization isn't possible with function templates.
However, it is possible with class templates.
So, as a first step, you could define parse as a static function of a struct, like this:
using std::istream;
using std::tuple;
using std::make_tuple;
struct A { A(const istream &) {} };
struct B { B(const istream &) {} };
template <typename... Args>
struct parser
{
/* Your original function, now inside a struct.
I'm using direct tuple construction and an
initializer list to circumvent the order-of-
construction problem mentioned in the comment
to your question. */
static tuple<Args...> parse(const istream &strm)
{ return tuple<Args...> {Args(strm)...}; }
};
template <typename... Args>
struct parser<tuple<Args...>>
{
/* Specialized for tuple. */
static tuple<Args...> parse(const istream &strm)
{ return parser<Args...>::parse(strm); }
};
You can then call it in the desired way:
int main()
{
typedef tuple<A,B> tuple_type;
auto tup = parser<tuple_type>::parse(std::cin);
return 0;
}
As a second step, you can define a function template (again) which passes the arguments on to the right specialization of the struct:
template <typename... Args>
auto parse(const istream &strm) -> decltype(parser<Args...>::parse(strm))
{ return parser<Args...>::parse(strm); }
And now you can use it in exactly the way you wanted:
int main()
{
typedef tuple<A,B> tuple_type;
auto tup = parse<tuple_type>(std::cin);
return 0;
}
(And you can still use it in the old way, too: auto tup = parse<A,B>(std::cin).)
Remark. As mentioned in the comment to parser::parse(), I used direct tuple construction instead of make_tuple to avoid problems with the order of construction of the tuple elements. This is not directly related to your question, but a good thing to do. See how to avoid undefined execution order for the constructors when using std::make_tuple.
There is a standard idiom for this kind of thing. [1]
// Define the "shape" of the template
template<typename Tuple> struct TupleMap;
// Specialize it for std::tuple
template<typename...T> struct TupleMap<std::tuple<T...>> {
using type = std::tuple<T...>; // not necessary but saves typing
// ... inside here, you have access to the parameter pac
}
Here's an example of using it, which might or might not fit your expectations (your example doesn't really indicate your expected use, since it lacks the typedef you promise in your question): liveworkspace.org.
Since litb raised the point, it is possible to force the tuple-components to be constructed in left-to-right order, illustrating another interesting idiom: comb inheritance. See lws.
(Since lws might disappear again, who knows, I'll paste the code here as well):
#include <iostream>
#include <tuple>
#include <type_traits>
#include <utility>
// Define the "shape" of the template
template<typename Tuple> struct TupleMap;
// Specialize it for std::tuple
template<typename...T> struct TupleMap<std::tuple<T...>> {
using type = std::tuple<T...>; // not necessary but saves typing
type value;
template<typename Arg>
TupleMap(Arg&& arg)
: value(T(std::forward<Arg>(arg))...) {
}
operator type() { return value; }
};
//Try it out:
using std::get; // Note 2
using Numbers = std::tuple<char, double, int>;
// Note 3
std::ostream& operator<<(std::ostream& out, const Numbers& n) {
return out << get<0>(n) << ' ' << get<1>(n) << ' ' << get<2>(n);
}
int main() {
std::cout << TupleMap<Numbers>(93.14159);
return 0;
}
[1] At least, I think it's a standard idiom. I use it a lot, and think of it as the "can-opener" pattern.
[2] This is needed (or at least, it's my style) to allow the use of get with tuple-like templates defined outside of std. Doing it this way allows ADL to find the appropriate definition of get without forcing me to add specializations to std::get. In this way, it's similar to the standard ADL idiom for begin and end.
[3] You can search SO for a cool hack to specialize operator<< for all tuples. There's a simpler one which can be used for specific tuples, but that's all off-topic for this question, so I just did something easy and dependency free. Note that this works because of the conversion operator in TupleMap
The basic approach is to create a sequence of indices 0, ..., std::tuple_size<Tuple>::value - 1 as a parameter pack Indices and call your function with parse<typename std::tuple_element<Tuple, Indices>::type...>(stream). You'd probably encapsulate the logic into a function parse_tuple<Tuple>(stream) (and some function this one delegates to) which in the end delegates to parse<...>(stream).
First, here is a class template and a function to create a sequence of indices based on the size of a std::tuple. The indices are needed to obtain a list of type from std::tuple:
template <int... Indices> struct indices;
template <>
struct indices<-1> { // for an empty std::tuple<> there is no entry
typedef indices<> type;
};
template <int... Indices>
struct indices<0, Indices...> { // stop the recursion when 0 is reached
typedef indices<0, Indices...> type;
};
template <int Index, int... Indices>
struct indices<Index, Indices...> { // recursively build a sequence of indices
typedef typename indices<Index - 1, Index, Indices...>::type type;
};
template <typename T>
typename indices<std::tuple_size<T>::value - 1>::type const*
make_indices() {
return 0;
}
With this in place, it is quite easy to extract the sequence of types from a std::tuple<T...>:
template<typename T, int... Indices>
T parse_tuple(std::istream &stream, indices<Indices...> const*) {
return parse<typename std::tuple_element<Indices, T>::type...>(stream);
}
template <typename T>
T parse_tuple(std::istream& stream) {
return parse_tuple<T>(stream, make_indices<T>());
}