I have a variadic class template
template <size_t ...T>
struct Foo
{
std::vector<size_t> t;
bool IsEqual()
{
//??
}
};
which I want to use like:
Foo<1,2,3,4> foo;
foo.data = {1,2,3,4};
foo.IsEqual();
How can I implement IsEqual to iterate and compare every element of the vector and return false / true if the elements are in the same order as the template parameters?
Use the index sequence trick:
bool IsEqual()
{
return t.size() == sizeof...(T) &&
IsEqual(std::make_index_sequence<sizeof...(T)>{});
}
with:
template <size_t... Is>
bool IsEqual(std::index_sequence<Is...> ) {
bool valid = true;
using expander = int[];
expander{0,
(valid = valid && t[Is] == T,
0)...
};
return valid;
}
Could even do this in one function by taking advantage of the fact that every value computation and side effect in an initializer-clause is sequenced before the next one by doing this in one go:
bool IsEqual()
{
if (t.size() == sizeof...(T)) {
auto it = t.begin();
bool valid = true;
using expander = int[];
expander{0,
(valid = valid && *it++ == T,
0)...
};
return valid;
}
else {
return false;
}
}
Simply unpack template arguments.
template <size_t ...T>
struct Foo
{
std::vector<size_t> t;
bool IsEqualTemplate(size_t index)
{
return true;
}
template <typename FIRSTARG, typename ...OTHERARGS>
bool IsEqualTemplate(size_t index, FIRSTARG firstArg, OTHERARGS... otherArgs)
{
return t[index] == firstArg && IsEqualTemplate(index + 1, otherArgs...);
}
bool IsEqual()
{
return t.size() == sizeof...(T) ? IsEqualTemplate(0, T...) : false;
}
};
Related
What's the correct way to write a specialization for an empty argument variadic template. Take bellow code as an example:
#include <iostream>
#include <memory>
#include <tuple>
#include <functional>
#include <cassert>
using namespace std;
struct message {
int type;
};
struct X: message {
int payload;
X(): message{1} {
}
};
struct Y: message {
int payload;
Y(): message{2} {
}
};
struct Z: message {
int payload;
Z(): message{3} {
}
};
template<typename T>
constexpr int message_type = -1;
template<>
constexpr int message_type<X> = 1;
template<>
constexpr int message_type<Y> = 2;
template<>
constexpr int message_type<Z> = 3;
struct M {
int payload;
M(int payload): payload{ payload } {
}
};
template<typename P, typename T1, typename... Ts>
tuple<int, unique_ptr<M>> helper(unique_ptr<message> &msg, function<int(unique_ptr<T1>&)> fn1, function<int(unique_ptr<Ts>&)>... fn) {
if (msg->type == message_type<T1>) {
unique_ptr<T1> m(static_cast<T1*>(msg.release()));
auto result = fn1(m);
return {result, make_unique<M>(m->payload)};
} else {
return helper<void, Ts...>(msg, fn...);
}
}
template<typename P>
tuple<int, unique_ptr<M>> helper(unique_ptr<message> &msg) {
assert(false);
return {0, unique_ptr<M>()};
}
template<typename... Ts>
tuple<int, unique_ptr<M>> dispatch_msg(unique_ptr<message> &msg, function<int(unique_ptr<Ts>&)> ...fn) {
return helper<void, Ts...>(msg, fn...);
}
int main() {
auto *real_message = new Z;
real_message->payload = 101;
unique_ptr<message> msg(real_message);
auto [result, m] = dispatch_msg<X, Y, Z>(msg, [](auto &x) {
return x->payload + 1;
}, [](auto &y) {
return y->payload + 2;
}, [](auto &z) {
return z->payload + 3;
});
cout << result << '\n' << m->payload << endl;
return 0;
}
The helper function takes variadic template arguments. If it checked all given type arguments and failed. e.g. run to the empty arguments. I want to assert and stop the process.
The current code works but I'm wondering is there any straightforward way to write a specialization.
I simplified the core requirements into the code below:
template<typename T, typename... Ts>
void func(int val, T arg, Ts... args) {
if (condition_hold<T>(val)) {
return;
} else {
return func<Ts...>(val, args...);
}
}
template<>
void func(int val) {
assert(false);
}
int main() {
func<int, double, float>(100);
return 0;
}
Basically the func is checking against every given type whether a condition hold for the input val. If all check failed I want to do something, like the assert here. So I wrote a specialization takes empty argument, but this can't compile.
In C++17, you don't need to split parameter packs into head and tail in most cases. Thanks to fold expressions, many operations on packs become much easier.
// Some generic predicate.
template <typename T>
bool condition_hold(T) {
return true;
}
// Make this whatever you want.
void do_something_with(int);
template<typename... Ts>
auto func(int val, Ts... args) {
// Fold expression checks whether the condition is true for all
// elements of the parameter pack.
// Will be true if the parameter pack is empty.
if ((condition_hold(args) && ...))
do_something_with(val);
}
int main() {
// Ts type parameters are deduced to <float, float>.
func(100, 1.f, 2.f);
return 0;
}
To check whether the pack was empty and handle this case specially, you can do:
template<typename... Ts>
auto func(int val, Ts... args) {
if constexpr (sizeof...(Ts) == 0) {
// handle empty pack
}
else {
// handle non-empty pack
}
}
Your specialization couldn't have worked because func<> needs to take at least one parameter. A specialization such as
template<typename T>
void func<T>(int val);
Wouldn't be valid either, because it wold be a partial specialization which is only allowed for classes.
However, if the base template only takes a pack, we can fully specialize it:
template<typename... Ts>
void func(int val, Ts... args);
template<>
void func<>(int val);
Can't use variant.index() in constexpr statements so need to iterate variant and return true if it can cast to some type or false if it's emtpy or contains zero value. Try this code, but seems index sequence is not variadic type and ... operator not available in this case.
template <typename T>
bool has_value(T value) noexcept {
if constexpr (std::is_convertible_v <T, bool>) {
return value;
}
else if constexpr (is_variant_v<T>) {
constexpr size_t N = std::variant_size_v<decltype(value)>;
using variant_sequence = typename std::make_index_sequence<0, N-1>::type;
bool __has_value = (( std::get<variant_sequence>(value), true) || variant_sequence... ) ;
return __has_value;
}
return false;
}
I think you want:
template <typename T>
bool has_value(T value) noexcept {
if constexpr (std::is_convertible_v <T, bool>) {
return value;
} else if constexpr (is_variant_v<T>) {
return std::visit([](const auto& elem){ return has_value(elem); }, value);
}
return false;
}
I need a dispatcher function, something like below
template<typename T>
T dispatcher() {
// if T is double
return _func_double();
// if T is int
return _func_int();
// if T is char*
return _func_char_pointer();
}
and will be used like below
// some code that use above dispatcher
template<typename T1, typename T2, typename T3>
void do_multiple_thing(T1 *a1, T2 *a2, T2 *a3) {
*a1 = dispatcher<T1>();
*a2 = dispatcher<T2>();
*a3 = dispatcher<T3>();
}
Could you tell me how to achieve that?
P.S.
- solution for builtin types only suffices.
- both preprocessing and template appoach is acceptable.
If you have compiler with C++17 support this snippet of code should work:
template<typename T>
T dispatcher() {
// if T is double
if constexpr (std::is_same<T, double>::value)
return _func_double();
// if T is int
if constexpr (std::is_same<T, int>::value)
return _func_int();
// if T is char*
if constexpr (std::is_same<T, char*>::value)
return _func_char_pointer();
}
Otherwise you will have to do template specialization, and make overload for each of parameters that you want
//only needed for static assert
template<typename T>
struct always_false : std::false_type {};
template<typename T>
T dispatcher()
{
//to make sure that on type you didn't overload you will have exception
throw std::exception("This type was not overloaded")
//static assert that will provide compile time error
static_assert(always_false<T>::value , "You must specialize dispatcher for your type");
}
//or to get compile time error without static assert
template<typename T>
T dispatcher() = delete; //the simplest solution
template<>
double dispatcher<double>()
{
return _func_double();
}
//... and so on for all other functions
In C++17, you might combine if constexpr and std::is_same:
template<typename T>
T dispatcher() {
if constexpr (std::is_same<T, double>::value) {
return _func_double();
} else if constexpr (std::is_same<T, int>::value) {
return _func_int();
} else if constexpr (std::is_same<T, char*>::value) {
return _func_char_pointer();
} else {
return {}; // or static_assert(always_false<T>::value); ?
}
}
Before, you might use specialization or tag dispatching with overload:
template<typename T>
T dispatcher() {
return {}; // or static_assert(always_false<T>::value); ?
}
template<>
double dispatcher() {
return _func_double();
}
template<>
int dispatcher() {
return _func_int();
}
template<>
char* dispatcher() {
return _func_char_pointer();
}
or
template<typename T> struct tag {};
template<typename T>
T dispatcher(tag<T>) = delete; // or { return {}; } ?
double dispatcher(tag<double>) { return _func_double(); }
int dispatcher(tag<int>) { return _func_int(); }
char* dispatcher(tag<char*>) { return _func_char_pointer(); }
// some code that use above dispatcher
template<typename T1, typename T2, typename T3>
void do_multiple_thing(T1 *a1, T2 *a2, T2 *a3) {
*a1 = dispatcher(tag<T1>());
*a2 = dispatcher(tag<T2>());
*a3 = dispatcher(tag<T3>());
}
template <typename T>
T fetch_magic_value();
template <>
int fetch_magic_value<int>() { return 23; }
template <>
char fetch_magic_value<char>() { return ' '; }
template <>
std::string fetch_magic_value<std::string>() { return "tada"; }
template<typename T>
void do_multiple_thing(T *x) {
*x = fetch_magic_value<T>();
}
template<typename T, typename... Args>
void do_multiple_thing(T *first, Args *...args)
{
do_multiple_thing(first);
do_multiple_thing(args...);
}
https://wandbox.org/permlink/v2NMhoy8v3q5VhRf
C++17 version:
https://wandbox.org/permlink/0pi08jvYF5vlIpud
If you need a generic solution for writing such dispatchers, something along the lines of this can be used:
// calls the first function that has return type `T` with no arguments
template <class T, class F, class... Fs>
constexpr T call_by_return_type(F&& f, Fs&&... fs) {
if constexpr (std::is_same_v<T, std::invoke_result_t<F>>) {
return f();
} else if constexpr (sizeof...(fs) > 0) {
return call_by_return_type<T>(std::forward<Fs>(fs)...);
} else {
static_assert(
sizeof(T) == 0,
"`T` must match at least one function's return type"
);
}
}
And then you can create dispatchers as a combination of functions (can be any function-object that is called with no arguments):
template <class T>
constexpr T dispatcher() {
return call_by_return_type<T>(
_func_double,
_func_int,
_func_char_pointer
);
}
Example in godbolt.org
Note: I assumed you already have _func_<return-type> functions that need to be grouped to form a dispatcher, otherwise I could think of more elegant interfaces.
I have a C++ method findID that uses templates, and I want to be able to run a condition in this method based on the input type. The template parameter U will either be of type int or type string. I want to run a different condition based on the type of ID.
The code I have is follows:
template <typename S>
template <typename U>
S * findID(U ID){
for (typename vector<S*>::collectionsIter element = collection.begin() ; element != collection.end(); ++element)
if((*element)->getID() == ID) return *element;
return NULL;
}
I want my code to do the following:
template <typename S>
template <typename U>
S * findID(U ID){
***if ID is an int:
for (typename vector<S*>::collectionsIter element = collection.begin() ; element != collection.end(); ++element)
if((*element)->getID() == ID) return *element;
***if ID is a string:
for (typename vector<S*>::collectionsIter element = collection.begin() ; element != collection.end(); ++element)
if((*element)->getStringID() == ID) return *element;
***else
return NULL;
}
The reason that I want to do this is because I want to be able to compare string variables of ID to the string method of getStringID(), and the int variables of ID to the int method of getID(). In addition I do not want to break these up into separate methods, so I am trying to use templates and these conditions to refactor it into 1 method.
Just use 2 overloads:
template <typename S>
S* findID(int ID){
for (auto* element : collection)
if (element->getID() == ID) return element;
return nullptr;
}
template <typename S>
S* findID(const std::string& ID){
for (auto* element : collection)
if (element->getStringID() == ID) return element;
return nullptr;
}
Here's one way to do it using C++17 if constexpr:
struct Foo {
int id;
std::string stringId;
int getId() const { return id; }
const std::string& getStringId() const { return stringId; }
};
template <typename Cont, typename T>
auto findId(const Cont& c, const T& id) {
const auto pred = [&id](const auto& x) {
if constexpr (std::is_convertible_v<T, std::string>)
return x.getStringId() == id;
else if constexpr (std::is_convertible_v<T, int>)
return x.getId() == id;
else
static_assert(false, "Unsupported id type.");
return false;
};
const auto findIt = std::find_if(begin(c), end(c), pred);
return findIt == end(c) ? nullptr : &(*findIt);
}
int main() {
using namespace std;
vector<Foo> foos{{1, "1"}, {2, "2"}, {3, "3"}};
auto foo2Int = findId(foos, 2);
auto foo2String = findId(foos, "2"s);
cout << foo2Int->id << ", " << foo2String->stringId << '\n';
}
I would like to define a simple template function which takes a runtime value and determines if it is a member of some set of possible values.
Usage:
int x; // <- pretend this came from elsewhere...
if (isoneof(x, {5,3,9,25}) ...
Something like:
template <typename T, size_t size>
bool isoneof(T value, T (&arr)[size])
{
for (size_t i = 0; i < size; ++i)
if (value == arr[i])
return true;
return false;
}
I assume that this is doomed to failure, as I don't see how one can create a static array inline.
I can use:
int kPossibilities[] = {5,3,9,25};
if (isoneodf(6, kPossibilities)) ...
With a minor change to isoneof:
template <typename T1, typename T2, size_t size>
bool isoneof(T1 value, const T2 (&arr)[size])
{
for (size_t i = 0; i < size; ++i)
if (value == arr[i])
return true;
return false;
}
Which also makes it a tad more flexible.
Does anyone have an improvement to offer? A better way to define a "set of static values inline"?
If you like such things, then you will be a very happy user of Boost.Assign.
Boost.Assign actually proves that such semantics are possible, however one look at the source of assign will convince you that you don't want to do that by yourself :)
You will be able to create something like this however:
if (isoneof(x, list_of(2)(3)(5)(7)(11)) { ...
... the downside being you'd have to use boost::array as the parameter instead of a built-in array (thanks, Manuel) -- however, that's a nice moment to actually start using them :>
It's possible in the next C++ standard.
Up till then, you can work around it by e.g. overloading operator, for a static object that starts a static array.
Note: this implementation is O(n^2) and may be optimized - it's just to get the idea.
using namespace std;
template< typename T, size_t N >
struct CHead {
T values[N];
template< typename T > CHead<T,N+1> operator,( T t ) {
CHead<T,N+1> newhead;
copy( values, values+N, newhead.values);
newhead.values[N]=t;
return newhead;
}
bool contains( T t ) const {
return find( values, values+N, t ) != values+N;
}
};
struct CHeadProto {
template< typename T >
CHead<T,1> operator,( T t ) {
CHead<T,1> h = {t};
return h;
}
} head;
int main()
{
assert( (head, 1,2,3,4).contains(1) );
return 0;
}
For the sake of completeness, I'll post a solution that uses Boost.MPL. The following works, but I think Kornel's solution is best.
#include <iostream>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/vector_c.hpp>
struct Contains
{
Contains(int value, bool& result) : value(value), result(result)
{
result = false;
}
template< typename T > void operator()(T x)
{
result = result || (x == value);
}
int value;
bool& result;
};
template <class IntList>
bool isoneof(int val)
{
namespace mpl = boost::mpl;
bool result;
mpl::for_each<IntList>(Contains(val, result));
return result;
}
int main()
{
namespace mpl = boost::mpl;
std::cout << isoneof< mpl::vector_c<int, 1,2,3,5,7,11> >(4) << "\n";
std::cout << isoneof< mpl::vector_c<int, 1,2,3,5,7,11> >(5) << "\n";
}
As you can see, the compile-time array is passed inline as a template argument to isoneof.
This one?
int ints[] = {2,3,5,7,11};
#define ARRAY_SIZE(Array) (sizeof(Array)/sizeof((Array)[0]))
#define INLIST(x,array) isoneof(x,array,ARRAY_SIZE(array))
ADDITION:
template <typename T>
bool isoneof(const T& x, T *array, int n)
{
for(int i=0; i<n; ++i)
if(x==array[i])
return true;
return false;
}
Using C++11, this would be written like this:
template <typename T>
bool isoneof(T value, std::initializer_list<T> arr)
{
using namespace std;
return any_of(begin(arr), end(arr), [&](const T& x) { return x == value; });
}
Just FYI - I solved my particular problem using vararg templates and initializer lists now that I have access to C++14:
template <typename T, typename U>
bool isoneof(T v, U v1) { return v == v1; }
template <typename T, typename U, typename... Args>
bool isoneof(T v, U v1, Args ... others) { return isoneof(v, v1) || isoneof(v, others...); }
template <typename T, typename U>
bool isoneof(T value, std::initializer_list<U> values)
{
for (const auto & e : values)
if (value == e)
return true;
return false;
}