I need to convert a tuple to a byte array. This is the code I use to convert to byte array:
template< typename T > std::array< byte, sizeof(T) > get_bytes( const T& multiKeys )
{
std::array< byte, sizeof(T) > byteArr ;
const byte* start = reinterpret_cast< const byte* >(std::addressof(multiKeys) ) ;
const byte* end = start + sizeof(T);
std::copy(start, end, std::begin(byteArr));
return byteArr;
}
Here is how I call it:
void foo(T... keyTypes){
keys = std::tuple<T... >(keyTypes...);
const auto bytes = get_bytes(keys);
}
I need to augment this code such that when a pointer is a part of the tuple, I dereference it to it's value and then pass the new tuple, without any pointers, to the get_bytes() function. How do I detect the presence of a pointer in the tuple? I can then iterate through the tuple and dereference it with:
std::cout << *std::get<2>(keys) << std::endl;
Add a trivial overload: T get_bytes(T const* t) { return getBytes(*t); }.
That would be easy with C++14 :
#include <iostream>
#include <tuple>
#include <utility>
template <class T> decltype(auto) get_dereferenced_value(T &&value) {
return std::forward<T>(value);
}
template <class T> decltype(auto) get_dereferenced_value(T *value) {
return *value;
}
template <class Tuple, class Indexes> struct get_dereferenced_tuple_impl;
template <class... Args, size_t... Index>
struct get_dereferenced_tuple_impl<std::tuple<Args...>,
std::integer_sequence<size_t, Index...>> {
decltype(auto) operator()(std::tuple<Args...> const &originalTuple) {
return std::make_tuple(
get_dereferenced_value(std::get<Index>(originalTuple))...);
}
};
template <class Tuple>
decltype(auto) get_dereferenced_tuple(Tuple const &tupleValue) {
return get_dereferenced_tuple_impl<
Tuple,
std::make_integer_sequence<size_t, std::tuple_size<Tuple>::value>>{}(
tupleValue);
}
int main() {
char c = 'i';
std::tuple<char, char *> t{'h', &c};
auto t2 = get_dereferenced_tuple(t);
std::cout << std::get<0>(t2) << std::get<1>(t2) << "\n";
return 0;
}
If you cannot use C++14, then you would have to write more verbose decltype expressions, as well as include an implementation of std::(make_)integer_sequence.
This has a drawback though : copies will be made before copying the bytes. A tuple of references is not a good idea. The most performant version would be a get_bytes able to serialize the entire mixed tuple directly.
Related
I have an application with several boost::variants which share many of the fields. I would like to be able to compose these visitors into visitors for "larger" variants without copying and pasting a bunch of code. It seems straightforward to do this for non-recursive variants, but once you have a recursive one, the self-references within the visitor (of course) point to the wrong class. To make this concrete (and cribbing from the boost::variant docs):
#include "boost/variant.hpp"
#include <iostream>
struct add;
struct sub;
template <typename OpTag> struct binop;
typedef boost::variant<
int
, boost::recursive_wrapper< binop<add> >
, boost::recursive_wrapper< binop<sub> >
> expression;
template <typename OpTag>
struct binop
{
expression left;
expression right;
binop( const expression & lhs, const expression & rhs )
: left(lhs), right(rhs)
{
}
};
// Add multiplication
struct mult;
typedef boost::variant<
int
, boost::recursive_wrapper< binop<add> >
, boost::recursive_wrapper< binop<sub> >
, boost::recursive_wrapper< binop<mult> >
> mult_expression;
class calculator : public boost::static_visitor<int>
{
public:
int operator()(int value) const
{
return value;
}
int operator()(const binop<add> & binary) const
{
return boost::apply_visitor( *this, binary.left )
+ boost::apply_visitor( *this, binary.right );
}
int operator()(const binop<sub> & binary) const
{
return boost::apply_visitor( *this, binary.left )
- boost::apply_visitor( *this, binary.right );
}
};
class mult_calculator : public boost::static_visitor<int>
{
public:
int operator()(int value) const
{
return value;
}
int operator()(const binop<add> & binary) const
{
return boost::apply_visitor( *this, binary.left )
+ boost::apply_visitor( *this, binary.right );
}
int operator()(const binop<sub> & binary) const
{
return boost::apply_visitor( *this, binary.left )
- boost::apply_visitor( *this, binary.right );
}
int operator()(const binop<mult> & binary) const
{
return boost::apply_visitor( *this, binary.left )
* boost::apply_visitor( *this, binary.right );
}
};
// I'd like something like this to compile
// class better_mult_calculator : public calculator
// {
// public:
// int operator()(const binop<mult> & binary) const
// {
// return boost::apply_visitor( *this, binary.left )
// * boost::apply_visitor( *this, binary.right );
// }
// };
int main(int argc, char **argv)
{
// result = ((7-3)+8) = 12
expression result(binop<add>(binop<sub>(7,3), 8));
assert( boost::apply_visitor(calculator(),result) == 12 );
std::cout << "Success add" << std::endl;
// result2 = ((7-3)+8)*2 = 12
mult_expression result2(binop<mult>(binop<add>(binop<sub>(7,3), 8),2));
assert( boost::apply_visitor(mult_calculator(),result2) == 24 );
std::cout << "Success mult" << std::endl;
}
I would really like something like that commented out better_mult_expression to compile (and work) but it doesn't -- because the this pointers within the base calculator visitor don't reference mult_expression, but expression.
Does anyone have suggestions for overcoming this or am I just barking down the wrong tree?
Firstly, I'd suggest the variant to include all possible node types, not distinguishing between mult and expression. This distinction makes no sense at the AST level, only at a parser stage (if you implement operator precedence in recursive/PEG fashion).
Other than that, here's a few observations:
if you encapsulate the apply_visitor dispatch into your evaluation functor you can reduce the code duplication by a big factor
your real question seems not to be about composing variants, but composing visitors, more specifically, by inheritance.
You can use using to pull inherited overloads into scope for overload resolution, so this might be the most direct answer:
Live On Coliru
struct better_mult_calculator : calculator {
using calculator::operator();
auto operator()(const binop<mult>& binary) const
{
return boost::apply_visitor(*this, binary.left) *
boost::apply_visitor(*this, binary.right);
}
};
IMPROVING!
Starting from that listing let's shave off some noise!
remove unncessary AST distinction (-40 lines, down to 55 lines of code)
generalize the operations; the <functional> header comes standard with these:
namespace AST {
template <typename> struct binop;
using add = binop<std::plus<>>;
using sub = binop<std::minus<>>;
using mult = binop<std::multiplies<>>;
using expr = boost::variant<int,
recursive_wrapper<add>,
recursive_wrapper<sub>,
recursive_wrapper<mult>>;
template <typename> struct binop { expr left, right; };
} // namespace AST
Now the entire calculator can be:
struct calculator : boost::static_visitor<int> {
int operator()(int value) const { return value; }
template <typename Op>
int operator()(AST::binop<Op> const& binary) const {
return Op{}(boost::apply_visitor(*this, binary.left),
boost::apply_visitor(*this, binary.right));
}
};
Here your variant can add arbitrary operations without even needing to touch the calculator.
Live Demo, 43 Lines Of Code
Like I mentioned starting off, encapsulate visitation!
struct Calculator {
template <typename... T> int operator()(boost::variant<T...> const& v) const {
return boost::apply_visitor(*this, v);
}
template <typename T>
int operator()(T const& lit) const { return lit; }
template <typename Op>
int operator()(AST::binop<Op> const& bin) const {
return Op{}(operator()(bin.left), operator()(bin.right));
}
};
Now you can just call your calculator, like intended:
Calculator calc;
auto result1 = calc(e1);
It will work when you extend the variant with operatios or even other literal types (like e.g. double). It will even work, regardless of whether you pass it an incompatible variant type that holds a subset of the node types.
To finish that off for maintainability/readability, I'd suggest making operator() only a dispatch function:
Full Demo
Live On Coliru
#include <boost/variant.hpp>
#include <iostream>
namespace AST {
using boost::recursive_wrapper;
template <typename> struct binop;
using add = binop<std::plus<>>;
using sub = binop<std::minus<>>;
using mult = binop<std::multiplies<>>;
using expr = boost::variant<int,
recursive_wrapper<add>,
recursive_wrapper<sub>,
recursive_wrapper<mult>>;
template <typename> struct binop { expr left, right; };
} // namespace AST
struct Calculator {
auto operator()(auto const& v) const { return call(v); }
private:
template <typename... T> int call(boost::variant<T...> const& v) const {
return boost::apply_visitor(*this, v);
}
template <typename T>
int call(T const& lit) const { return lit; }
template <typename Op>
int call(AST::binop<Op> const& bin) const {
return Op{}(call(bin.left), call(bin.right));
}
};
int main()
{
using namespace AST;
std::cout << std::boolalpha;
auto sub_expr = add{sub{7, 3}, 8};
expr e1 = sub_expr;
expr e2 = mult{sub_expr, 2};
Calculator calc;
auto result1 = calc(e1);
std::cout << "result1: " << result1 << " Success? " << (12 == result1) << "\n";
// result2 = ((7-3)+8)*2 = 12
auto result2 = calc(e2);
std::cout << "result2: " << result2 << " Success? " << (24 == result2) << "\n";
}
Still prints
result1: 12 Success? true
result2: 24 Success? true
Boost's program_options library now supports boost::optional, can the same be done with std::optional?
I attempted to modify both the documentation example and the code in the PR, but neither seems to work.
For example, the very simple case for integers (before trying template specializations):
void validate(boost::any& v, const std::vector<std::string>& values, std::optional<int>* target_type,
int) {
using namespace boost::program_options;
validators::check_first_occurrence(v);
const string& s = validators::get_single_string(values);
int n = lexical_cast<int>(s);
v = any(std::make_optional<int>(n));
}
fails with the error that the target type is not istreamable:
external/boost/boost/lexical_cast/detail/converter_lexical.hpp:243:13:
error: static_assert failed due to requirement
'has_right_shift<std::__1::basic_istream<char>, std::__1::optional<int>, boost::binary_op_detail::dont_care>::value || boost::has_right_shift<std::__1::basic_istream<wchar_t>, std::__1::optional<int>, boost::binary_op_detail::dont_care>::value'
"Target type is neither std::istream`able nor std::wistream`able"
The problem with things like validate (and operator>> as well) is often ADL¹.
You need to declare the overload in one of the associated namespaces. In this case, because int is a primitive type, the only associated namespaces come from library code:
std for optional, vector, string, allocator, char_traits (yes these all count!)
boost for any
You'd prefer not to add your code in those namespaces, because you might interfere with library functions or invite future breakage when the library implementation details change.
If you had to choose, you'd prefer to choose boost here, because
that's the library providing the feature at hand
the validate free function is explicitly designed to be an customization point
Sidenote: Keep an eye out for tag_invoke - a better way to build customization points in libraries
The Fix
After all this verbiage, the solution is very simple:
namespace boost {
void validate(boost::any& v, const std::vector<std::string>& values,
std::optional<int>*, int) {
using namespace boost::program_options;
validators::check_first_occurrence(v);
const std::string& s = validators::get_single_string(values);
int n = boost::lexical_cast<int>(s);
v = boost::any(std::make_optional<int>(n));
}
} // namespace boost
Adding two lines made it work: Live On Wandbox.
Other Notes:
The "solution" injecting operator>> in general is less pure
because
it has a potential to "infect" all other code with ADL-visible overloads that might interfere. Way more code uses operator>> than
boost's validate function
it thereby invites UB due to
ODR violations,
when another translation unit, potentially legitimely, defines
another operator>> for the same arguments.
On recent compilers you can say vm.contains instead of the slightly abusive vm.count
There's another snag with non-streamable types, where, if you define a default value, you probably also need to specify the string representation with it.
Listing
Compiling on Compiler Explorer
#include <boost/program_options.hpp>
#include <optional>
#include <iostream>
namespace po = boost::program_options;
namespace boost {
void validate(boost::any& v, const std::vector<std::string>& values,
std::optional<int>*, int) {
using namespace boost::program_options;
validators::check_first_occurrence(v);
const std::string& s = validators::get_single_string(values);
int n = boost::lexical_cast<int>(s);
v = boost::any(std::make_optional<int>(n));
}
} // namespace boost
int main(int ac, char* av[]) {
try {
using Value = std::optional<int>;
po::options_description desc("Allowed options");
desc.add_options()
("help", "produce help message")
("value", po::value<Value>()->default_value(10, "10"),
"value")
;
po::variables_map vm;
po::store(po::parse_command_line(ac, av, desc), vm);
po::notify(vm);
if (vm.contains("value")) {
std::cout << "value is " << vm["value"].as<Value>().value() << "\n";
}
} catch (std::exception& e) {
std::cout << e.what() << "\n";
return 1;
}
}
BONUS
As an added exercise, let's demonstrate that if your optional value_type is not a primitive, but rather your library type, declared in a namespace MyLib, then we don't have most of the trade-offs above:
namespace MyLib {
template <typename T> struct MyValue {
MyValue(T v = {}) : value(std::move(v)) {}
private:
T value;
friend std::istream& operator>>(std::istream& is, MyValue& mv) {
return is >> mv.value;
}
friend std::ostream& operator<<(std::ostream& os, MyValue const& mv) {
return os << mv.value;
}
};
Now you could provide generic validators for any types in your MyLib namespace, be it optional or not, and have ADL find them through your MyLib namespace:
template <typename T, typename Values>
void validate(boost::any& v, Values const& values, T*, int) {
po::validators::check_first_occurrence(v);
v = boost::lexical_cast<T>(
po::validators::get_single_string(values));
}
template <typename T, typename Values>
void validate(boost::any& v, Values const& values, std::optional<T>*, int) {
po::validators::check_first_occurrence(v);
v = std::make_optional(
boost::lexical_cast<T>(
po::validators::get_single_string(values)));
}
} // namespace MyLib
See Live Demo
#include <boost/program_options.hpp>
#include <iostream>
#include <iomanip>
namespace po = boost::program_options;
namespace MyLib {
template <typename T> struct MyValue {
MyValue(T v = {}) : value(std::move(v)) {}
private:
T value;
friend std::istream& operator>>(std::istream& is, MyValue& mv) {
return is >> std::boolalpha >> mv.value;
}
friend std::ostream& operator<<(std::ostream& os, MyValue const& mv) {
return os << std::boolalpha << mv.value;
}
};
// Provide generic validators for any types in your MyLib namespace, be it
// optional or not
template <typename T, typename Values>
void validate(boost::any& v, Values const& values, T*, int) {
po::validators::check_first_occurrence(v);
v = boost::lexical_cast<T>(
po::validators::get_single_string(values));
}
template <typename T, typename Values>
void validate(boost::any& v, Values const& values, std::optional<T>*, int) {
po::validators::check_first_occurrence(v);
v = std::make_optional(
boost::lexical_cast<T>(
po::validators::get_single_string(values)));
}
} // namespace MyLib
int main(int ac, char* av[]) {
try {
using Int = MyLib::MyValue<int>;
using OptInt = std::optional<MyLib::MyValue<int>>;
using OptStr = std::optional<MyLib::MyValue<std::string> >;
po::options_description desc("Allowed options");
desc.add_options()
("ival", po::value<Int>()->default_value(Int{10}),
"integer value")
("opti", po::value<OptInt>()->default_value(OptInt{}, "(nullopt)"),
"optional integer value")
("sval", po::value<OptStr>()->default_value(OptStr{"secret"}, "'secret'"),
"optional string value")
;
po::variables_map vm;
po::store(po::parse_command_line(ac, av, desc), vm);
po::notify(vm);
std::cout << "Options: " << desc << "\n";
if (vm.contains("ival")) {
std::cout << "ival is " << vm["ival"].as<Int>() << "\n";
}
if (vm.contains("opti")) {
if (auto& v = vm["opti"].as<OptInt>())
std::cout << "opti is " << v.value() << "\n";
else
std::cout << "opti is nullopt\n";
}
if (vm.contains("sval")) {
if (auto& v = vm["sval"].as<OptStr>())
std::cout << "sval is " << v.value() << "\n";
else
std::cout << "sval is nullopt\n";
}
} catch (std::exception& e) {
std::cout << e.what() << "\n";
return 1;
}
}
For ./a.out --ival=42 --sval=LtUaE prints:
Options: Allowed options:
--ival arg (=10) integer value
--opti arg (=(nullopt)) optional integer value
--sval arg (='secret') optional string value
ival is 42
opti is nullopt
sval is LtUaE
¹ see also See also Why Does Boost Use a Global Function Override to Implement Custom Validators in "Program Options"
I have a tensor classes of rank N which wrap data stored in an array. For example, a rank-3 tensor would have dimensions (d0,d1,d2) and a unique element would be accessed with the multi-index (i0,i1,i2) from the underlying array of length d0*d1*d2. If d0=d1=d2=10, i0=1, i1=2, i2=3, then element 123 of the array would be accessed.
I've implemented a recursively defined class which computes single array index from the multi-index as follows:
template<size_t N>
class TensorIndex : TensorIndex<N-1> {
private:
size_t d;
public:
template<typename...Ds>
TensorIndex( size_t d0, Ds...ds ) : TensorIndex<N-1>( ds... ), d(d0) {}
template<typename...Is>
size_t index( size_t i0, Is...is ) {
return i0+d*TensorIndex<N-1>::index(is...);
}
};
template<>
struct TensorIndex<1> {
TensorIndex( size_t ) {}
size_t index( size_t i ) { return i; }
};
Which reverses the desired order.
TensorIndex<3> g(10,10,10);
std::cout << g.index(1,2,3) << std::endl;
outputs 321. What would be a simple way to reverse the order of the arguments for the constructor and index functions?
Edit:
I tried implementing using the suggested approach of reversing the variadic arguments, but this was suboptimal as it required reversing the arguments for both index and the constructor and the necessary helper functions for these two cases would appear slightly different. The initializer list answer looks more straightforward.
No need of recursion nor to reverse, you can use initializer-list to call an evaluation function that accumulates index from left to right. The function object called in the initalizer-list should have a non-void return type :
#include <cstddef>
#include <iostream>
using namespace std;
template<size_t N>
class TensorIndex {
public:
template<typename... Args>
TensorIndex(Args... args) : dims{static_cast<size_t>(args)...}
{
static_assert(sizeof...(Args) == N,
"incorrect number of arguments for TensorIndex constructor");
}
template<typename... Args>
size_t index(Args... args) {
static_assert(sizeof...(Args) == N,
"incorrect number of arguments for TensorIndex::index()");
IndexEval eval{dims};
Pass pass{eval(args)...}; // evaluate from left to right : initializer-list
return eval.get_res();
}
private:
const size_t dims[N];
class IndexEval {
size_t k = 0;
size_t res = 0;
const size_t* dims;
public:
IndexEval(const size_t* dims) : dims{dims} {}
size_t operator()(size_t i) {
return res = res * dims[k++] + i;
}
size_t get_res() const { return res; }
};
struct Pass {
template<typename... Args> Pass(Args...) {}
};
};
int main()
{
TensorIndex<3> g(10, 10, 10);
cout << g.index(1, 2, 3) << endl;
}
Boost Fusion has been designed in such a way that most of the transformations are "lazy", in the sense that they all generate "views" but not actual (Fusion) containers (http://www.boost.org/doc/libs/1_58_0/libs/fusion/doc/html/fusion/algorithm.html). So for example to actually reverse a vector one needs to use the conversion function as_vector (http://www.boost.org/doc/libs/1_58_0/libs/fusion/doc/html/fusion/container/conversion/functions.html).
boost::fusion::vector<int, double, std::string> vec;
auto view_rev = boost::fusion::reverse(vec); // view object
auto vec_rev = boost::fusion::as_vector(view_rev);
Now, I want to do this with adapted std::tuple:
#include<boost/fusion/adapted/std_tuple.hpp>
...
std::tuple<int, double, std::string> tup;
auto view_rev = boost::fusion::reverse(tup);
auto tup_rev = boost::fusion::???(view_rev); // type should be of type std::tuple<std::string, double, int>
How do I convert the resulting view back to a tuple?
I expected this ??? function to be called as_std_tuple (in analogy to boost::fusion::as_vector, but it doesn't exists (yet?).
There a few solutions for reversing tuples, in this case I want just to use what is already in Boost Fusion.
I am not aware of any built-in method to convert a Boost Fusion Sequence into a std::tuple, but using the indices trick it can be implemented rather easily:
template <std::size_t... Is>
struct indices {};
template <std::size_t N, std::size_t... Is>
struct build_indices
: build_indices<N-1, N-1, Is...> {};
template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};
template<typename Sequence, std::size_t ...Is>
auto as_std_tuple_impl(const Sequence& s, indices<Is...>&&) -> decltype(std::tie(boost::fusion::at_c<Is>(s)...))
{
return std::tie(boost::fusion::at_c<Is>(s)...);
}
template <typename Sequence, typename Indices = build_indices<boost::fusion::result_of::size<Sequence>::value>>
auto as_std_tuple(const Sequence& s) -> decltype(as_std_tuple_impl(s, Indices()))
{
return as_std_tuple_impl(s, Indices());
}
Here is a full example that reverses an adapted std::tuple using boost::fusion::reverse and converts it back into a std::tuple and prints both tuples:
#include <tuple>
#include <utility>
#include<boost/fusion/adapted/std_tuple.hpp>
#include <boost/fusion/algorithm/transformation/reverse.hpp>
#include <boost/fusion/include/reverse.hpp>
#include <boost/fusion/sequence/intrinsic/size.hpp>
#include <boost/fusion/include/size.hpp>
#include <iostream>
template <std::size_t... Is>
struct indices {};
template <std::size_t N, std::size_t... Is>
struct build_indices
: build_indices<N-1, N-1, Is...> {};
template <std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};
template<typename Sequence, std::size_t ...Is>
auto as_std_tuple_impl(const Sequence& s, indices<Is...>&&) -> decltype(std::tie(boost::fusion::at_c<Is>(s)...))
{
return std::tie(boost::fusion::at_c<Is>(s)...);
}
template <typename Sequence, typename Indices = build_indices<boost::fusion::result_of::size<Sequence>::value>>
auto as_std_tuple(const Sequence& s) -> decltype(as_std_tuple_impl(s, Indices()))
{
return as_std_tuple_impl(s, Indices());
}
template<class Tuple, std::size_t N>
struct TuplePrinter
{
static void print(const Tuple& t)
{
TuplePrinter<Tuple, N-1>::print(t);
std::cout << ", " << std::get<N-1>(t);
}
};
template<class Tuple>
struct TuplePrinter<Tuple, 1>
{
static void print(const Tuple& t)
{
std::cout << std::get<0>(t);
}
};
template<class... Args>
void print(const std::tuple<Args...>& t)
{
std::cout << "(";
TuplePrinter<decltype(t), sizeof...(Args)>::print(t);
std::cout << ")\n";
}
int main()
{
std::tuple<int, double, std::string> tup(1,2.5,"hello");
auto view_rev = boost::fusion::reverse(tup);
auto reversed_tup = as_std_tuple(view_rev);
print(tup);
print(reversed_tup);
return 0;
}
output:
(1, 2.5, hello)
(hello, 2.5, 1)
Live example on ideone
I have some code which, very much simplified, looks somewhat like this:
#include <iostream>
#include <type_traits>
namespace X {
struct Foo {int x;};
struct Bar {int x;};
template <typename T , typename = typename std::enable_if<
std::is_same<decltype(T::x),int>::value
>::type>
std::ostream & operator<<(std::ostream & os, const T&) {
return os;
}
}
namespace Y {
struct Faa : X::Foo {int y;};
struct Baz {int x; int y;};
template <typename T , typename = typename std::enable_if<
std::is_same<decltype(T::x),int>::value &&
std::is_same<decltype(T::y),int>::value
>::type>
std::ostream & operator<<(std::ostream & os, const T&) {
return os;
}
}
int main() {
// Everything is ok
X::Foo x;
std::cout << x;
Y::Baz k;
std::cout << k;
// Problems..
Y::Faa y;
// std::cout << y; // <--operator is ambiguous
Y::operator<<(std::cout, y);
return 0;
}
Is there any way to avoid the ambiguous operator for Y::Faa and having to manually specify Y::operator<<? If not, why?
Two functions have a conflict because conditions on their arguments have non-empty intersection (actually, 1st supersedes 2nd). Function overloading works only if signatures are different. So, to solve this we have 2 options:
Change conditions so that they have empty intersection (manually forbid having y field by adding && !sfinae_has_member_y<T>::value condition to the 1st enable_if)
template<typename T>
struct sfinae_has_member_y {
static int has(...);
template<typename U = T, typename = decltype(U::y)>
static char has(const U& value);
enum { value = sizeof(char) == sizeof(has(std::declval<T>())) };
};
OR use another C++ feature that supports arguments overlapping, like struct/class template specialization. If you replace bool with int, other fields may be added too:
template<typename T, bool>
struct Outputter {
};
template<typename T>
struct Outputter<T, false> {
static std::ostream & output(std::ostream & os, const T&) {
os << "x";
return os;
}
};
template<typename T>
struct Outputter<T, true> {
static std::ostream & output(std::ostream & os, const T&) {
os << "y";
return os;
}
};
template<typename T, typename = std::enable_if_t<std::is_same<decltype(T::x), int>::value>>
std::ostream & operator<<(std::ostream & os, const T& a) {
return Outputter<T, sfinae_has_member_y<T>::value>::output(os, a);
}