问题
I want to use if constexpr
instead of tag dispatching, but I am not sure how to use it. Example code below.
template<typename T>
struct MyTag
{
static const int Supported = 0;
};
template<>
struct MyTag<std::uint64_t>
{
static const int Supported = 1;
};
template<>
struct MyTag<std::uint32_t>
{
static const int Supported = 1;
};
class MyTest
{
public:
template<typename T>
void do_something(T value)
{
// instead of doing this
bool supported = MyTag<T>::Supported;
// I want to do something like this
if constexpr (T == std::uint64_t)
supported = true;
}
};
回答1:
One way is to define a constexpr predicate which checks the type of its argument, then constexpr switch on the result of that predicate.
I think this way is nice because it separates the functional logic from the precondition logic.
#include <iostream>
#include <cstddef>
#include <type_traits>
class MyTest
{
public:
template<typename T>
void do_something(T value)
{
// define our predicate
// lambdas are constexpr-if-possible in c++17
constexpr auto is_supported = [](auto&& x) {
if constexpr (std::is_same<std::decay_t<decltype(x)>, std::uint64_t>())
return true;
else
return false;
};
// use the result of the predicate
if constexpr (is_supported(value))
{
std::cout << "supported\n";
}
else
{
std::cout << "not supported\n";
}
}
};
int main()
{
auto t = MyTest();
t.do_something(int(0));
t.do_something(std::uint64_t(0));
t.do_something(double(0));
t.do_something(static_cast<unsigned long>(0)); // be careful with std::uint_xx aliases
}
example results:
not supported
supported
not supported
supported
Another way to express this might be:
class MyTest
{
public:
template<class T>
static constexpr bool something_possible(T&&)
{
return std::is_same<std::decay_t<T>, std::uint64_t>();
}
template<typename T>
void do_something(T value)
{
// switch behaviour on result of constexpr predicate
if constexpr (something_possible(value))
{
std::cout << "supported\n";
}
else
{
std::cout << "not supported\n";
}
}
};
回答2:
Usually runtime interrogation of types has sense in functional programing with generic lambdas (with generic arguments too). Otherwise simple answer might be: just declare using 'required' types or use type traits, etc ... Back to the subject of generic lambdas.
/// <summary>
/// c++ 17 generic lambdas have issues
/// with required types of auto arguments
/// in c++20 this will be fixed with new
/// lambda arguments template declaration syntax
/// until then ...
/// </summary>
namespace required_types
{
template<typename RQ>
inline auto is_required_type = [](const auto & v_ = 0) constexpr -> bool
{
using T = std::decay_t< decltype(v_) >;
return std::is_same<T, RQ>();
};
inline auto is_uint64 = [] ( const auto & v_ = 0 ) constexpr -> bool
{
return is_required_type<std::uint64_t>(v_);
};
} // required_types
namespace {
using namespace required_types;
inline auto tv = [](const char prompt[] = "", const auto & value) {
std::cout << prompt << "\ntype:\t" << typeid(decltype(value)).name() << "\nvalue:\t" << value;
};
inline auto make_double_value = [](auto value)
{
if constexpr (is_uint64(value)) {
tv("\n\nDoubling required type (std::uint_64):", value);
return value + value;
}
tv("\n\nWill try to double 'illegal' type", value);
return value + value;
};
}
some usage
// call with 'legal' aka required type
std::uint64_t u42 = 42u;
auto double_value_2 = make_double_value(u42);
tv("\nResult:", double_value_2);
// call with some 'illegal' types also works
auto double_value = make_double_value(42u);
tv("\nResult:", double_value);
std::string one{"--ONE--"};
auto double_value_3 = make_double_value(one);
tv("\nResult:", double_value_3 );
Of course if one hotly disagrees with my intro one can still use my "required_types":
template<typename T>
void some_proc ( const T && val_ ) {
using namespace required_types;
if constexpr ( is_required_type<std::uint64_t>(val_) ) {
do_something_with_uint64 (val_) ;
}
}
Instead of above I would much rather use std::enable_if, somewhere along this answer.
But (as mentioned) for solving few generic lambdas issues in C++17 I would (boldly) use my namespace required_types, with some extensions.
来源:https://stackoverflow.com/questions/46169709/if-constexpr-instead-of-tag-dispatch