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;
}
Related
I have the following use case:
template<typename T>
struct Foo
{
bool setValue(T const &iValue)
{
if(fValue != iValue)
{
fValue = iValue;
return true;
}
return false;
}
T fValue;
};
which works only as long as T provides a operator!= implementation (and I suppose one of the complication is that operator!= can be implemented as member function of T or not...).
Ideally I would like to write something like this using C++ 17 if constexpr syntax
template<typename T>
struct Foo
{
bool setValue(T const &iValue)
{
if constexpr (is_diff_operator_defined<T>::value) {
if(fValue != iValue)
{
fValue = iValue;
return true;
}
} else {
fValue = iValue;
return true;
}
return false;
}
T fValue;
};
How would I go about it? Please note I am using C++ 17 so would prefer a solution that uses the latest and greatest feature (likes if constexpr which makes the code a lot easier to read/comprehend than optional dummy template function parameters we usually see with sfinae...)
With the detection idiom it's quite simple to do:
template<typename T>
using operator_not_eq_t = decltype(std::declval<T const&>() != std::declval<T const&>());
template<typename T>
constexpr auto is_diff_operator_defined = is_detected_v<operator_not_eq_t, T>;
Then simply use it with if constexpr as you wrote. (minus ::value)
Note that with concepts you can simply do that inline:
if constexpr (requires { fValue != iValue; }) {
if (fValue != iValue) {
// ...
}
}
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 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;
}
};
I want to build function, like as:
template< int ... values>
constexpr bool check( int i ) noexcept
{
switch(i)
{
case values[0]: case values[1]: ... case values[n-1] : // only illustrated.
return true;
default: return false;
}
}
Can I make that function?
UPDATE: thanks, now i know how to implement:
template< int ... values> struct checker;
template< int head, int ... tail> struct checker<head, tail...>
{
static constexpr bool apply( int i ) noexcept {
return i == head || checker<tail...>::apply(i);
}
};
template<> struct checker<>
{
static constexpr bool apply( int ) noexcept { return false; }
};
template< int ... values >
constexpr bool check(int i) noexcept { return checker<values...>::apply(i); }
UPDATE2: I don't know, it's good or not, but i found this solution :
template<size_t N>
constexpr bool any_of( bool( && array)[N], size_t index = 0) noexcept
{
return (index == N ) ? false
: ( array[index] || any_of( std::forward< decltype(array)>(array), 1+index) );
}
template< int ... values >
constexpr bool check(int i) noexcept
{
using list = bool[sizeof...(values)];
return any_of( list{ ( i == values) ... } );
}
template<>
constexpr bool check <>(int i) noexcept { return false; }
I don't think it's possible to use the switch syntax in any way. But this should work:
template < int head, int ... values >
struct checker
{
static constexpr bool value(int i) noexcept
{ return i == head || checker<values...>::value(i); }
};
template < int head >
struct checker<head>
{
static constexpr bool value(int i) noexcept
{ return i == head; }
};
template< int ... values>
constexpr bool check( int i ) noexcept
{
return checker<values...>::value(i);
}
Live example