'Reflection' using structured-bindings - c++

I was wondering if it was possible to use fact that in
struct Foo
{
int x;
};
int main()
{
Foo foo;
auto [a0] = foo;
auto [a1, b1] = foo;
auto [a2, b2, c2] = foo;
// auto [a, b, c, ...] = foo;
}
only the first structured-binding is valid, in order to create metafunction that takes any pod type and returns a tuple consisting of all the member types of the passed pod, e.g. for Foo it would return
std::tuple<int>
I tried something like this, but that didn't work out:
#include <tuple>
#include <type_traits>
#include <utility>
using namespace std;
template<typename T, typename U = void>
struct to_tuple;
template<typename T>
struct to_tuple<T, void_t<decltype([](T x) {
auto [a] = x;
return make_tuple(a);
}(declval<T>()))>>
{
using type = decltype([](T x) {
auto [a] = x;
return make_tuple(a);
}(declval<T>()));
};
template<typename T>
struct to_tuple<T, void_t<decltype([](T x) {
auto [a, b] = x;
return make_tuple(a, b);
}(declval<T>()))>>
{
using type = decltype([](T x) {
auto [a, b] = x;
return make_tuple(a, b);
}(declval<T>()));
};
template<typename T>
using to_tuple_t = typename to_tuple<T>::type;
struct Bar1
{
int x;
};
struct Bar2
{
int x;
float y;
};
int main()
{
static_assert(is_same_v<to_tuple_t<Bar1>, tuple<int>>);
static_assert(is_same_v<to_tuple_t<Bar2>, tuple<int, float>>);
}

The main issue here is that a structured bindings declaration is just that -- a declaration. We cannot form a "structured binding expression" in order to get the type, which is required in metaprogramming to constrain a template (for e.g., the void_t pattern, or a concept/requires clause)
Per [dcl.struct.bnd], despite the presence of an assignment-expression, a structured binding is distinctly a declaration.
Template metaprogramming relies on types, and a declaration is without a type.
You cannot for example say decltype(int a = 10) or even decltype(int a) for this reason.
You can say decltype(int{}) because now we have an expression.
For this reason, your void_t pattern does not work.
Unfortunately concepts/constraints don't help us, because we cannot have a declaration inside a requires clause (per [gram.expr])
Personally I think it's a bit of an oversight that we cannot have the equivalent of int{} for structured bindings. But then again, reflection is on its way anyway, so the point is probably moot.
Edit: As dfri pointed out, there is a GNU extension called statement expressions that can make this possible (as an extension it is understandably not portable code)

Related

What is the best way to disable implicit conversion from pointer types to bool when constructing an std::variant?

Consider the following:
struct foo {
};
struct bar {
};
int main()
{
foo f;
bar b;
std::variant<foo*, bool> v;
v = &b; // compiles in Visual Studio 19 v16.7.3
}
As discussed in comments, I believe the above is legal C++17. There is a proposal, P0608R3, that was accepted into the standard addressing this kind of surprising behavior, but it was accepted in 2018 (at the San Diego meeting) and thus applies to C++20 not C++17. Further P0608R3 is not currently implemented in Visual Studio, even when compiling to the C++20 preview.
What is the best / least verbose way to make creation of this variant from a pointer that points to a non-foo a compile time error?
I believe the following works but is a lot of boilerplate if the variant contains several items.
struct foo {
};
struct bar {
};
using variant_type = std::variant<foo*, bool>;
struct var_wrapper : public variant_type
{
var_wrapper(foo* v = nullptr) : variant_type(v)
{}
var_wrapper(bool v) : variant_type(v)
{}
template<typename T>
var_wrapper(T*) = delete;
};
int main()
{
foo f;
bar b;
var_wrapper vw;
vw = &f; // fine
vw = true; // fine
vw = &b; // compile time error
}
Am I missing some simpler way?
Another solution is to introduce another bool wrapper that doesn't construct from anything except from bool:
#include <variant>
struct foo {};
struct bar {};
struct StrongBool {
bool value = false;
StrongBool() noexcept = default;
StrongBool(bool b) noexcept : value(b) {}
template<class T>
StrongBool(T) = delete;
};
int main() {
foo f;
bar b;
std::variant<foo*, StrongBool> v;
v = true;
v = &f;
v = &b; // fails to compile
}
Regardless, limiting acceptable initializers requires introducing type wrappers with user-defined constructors.
I think the cleanest way to handle implicit conversion doing surprising things with respect to variants is to use a "strong variant" type if the behavior of std::variant is a problem; i.e., implement a variant type that enforces construction only using types that are exactly the types in the variant.
It is easy to test if a type is a member of a parameter pack in C++17 using std::disjunction, leading to an implementation as below:
template<typename... Ts>
class strong_variant : public std::variant<Ts...>
{
public:
template <typename T, typename U =
typename std::enable_if<std::disjunction_v<std::is_same<T, Ts>...>>::type>
strong_variant(T v) : std::variant<Ts...>(v)
{}
strong_variant() : std::variant<Ts...>()
{}
};
struct foo {};
struct bar {};
int main()
{
foo f;
bar b;
const foo c_f;
strong_variant<foo*, std::string, bool> sv;
sv = &f; // okay.
sv = true; // okay.
sv = "foo"s; // okay.
sv = "foo"; //no, must a string.
sv = &b; // no, must be a foo.
sv = &c_f; // no, must be non-const.
}

Explicit instantiation of function with auto->decltype approach

I want to create template function that would be able to extract any property of struct A.
Here is Source.h
struct B
{
int bbb;
};
struct C
{
double ccc;
};
struct A
{
B b;
C c;
};
template <class R>
auto foo(A* str, R getter) -> decltype(str->*getter);
Now I want use explicit instantiation approach for foo
Here comes Source.cpp:
#include "Source.h"
template <class R>
auto foo(A* str, R getter) -> decltype(str->*getter)
{
return str->*getter;
}
If we look at Main.cpp, we can see, that without explicit instantiation in the code block above we get link error:
//MAIN.cpp
#include "Source.h"
void main()
{
A a;
a.b.bbb = 7;
auto z = foo(&a, &A::b);
}
Now my question is how to explicitly instantiate foo for &A::b and &A::c types.
I have tried tons of variants but nothing works. I am in visual studio 2015.
P.S. Oh, and one more. Can we make foo with default argument for
R = decltype(&A::b) ?
There you go:
template B &foo(A*, B A::*);
template C &foo(A*, C A::*);
As for the default argument, you need defaults for both the type and the value:
template <class R = B A::*>
auto foo(A* str, R getter = &A::b) -> decltype(str->*getter);

Getting return type of an overloaded member function

I am trying to determine the return type of an overloaded member function to later use that type in my function template (see the example below). Cannot figure out how to do it using C++11 templating machinery (without modifying the definitions for struct A and B in the code below). Is this doable (in C++11 in general and MSVS2013 in particular) and how?
struct A{};
struct B{};
struct X
{
double f(A&);
int* f(B&);
};
template<typename T, typename R = /*??? what X::f(T) returns ???*/>
R ff(T& arg)
{
X x;
R r = x.f(arg); // preferably if I can create local variables of type R here
return r;
}
int main()
{
A a; ff(a);
B b; ff(b);
}
You can use decltype() for this, using std::declval to simulate values of the types needed to create the method call expression:
typename R = decltype(std::declval<X>().f(std::declval<T&>()))
Here is a demo that outputs the type ID of R; you can see that it correctly deduces double and int * for ff(a) and ff(b) respectively.
Side note: the entire body of your template function can be reduced to return X().f(arg);.
You can also use C++14 auto return type deduction like this:
template<typename T>
auto ff(T& arg)
{
X x;
auto r = x.f(arg);
return r;
}
In C++11, you can use the late return type:
template <typename T>
auto ff(T&& arg) -> decltype(std::declval<X>().f(arg))
{
return X().f(arg);
}
In C++14, you can even omit the late return type and let the compiler determine everything itself, like in Baum mit Augen's answer.
Edit: made the late return type work for non-default constructable types X.

what's the boost::type definition?

struct F
{
int operator()(int a, int b) { return a - b; }
bool operator()(long a, long b) { return a == b; }
};
F f;
int x = 104;
bind<int>(f, _1, _1)(x); // f(x, x), i.e. zero
Some compilers have trouble with the bind(f, ...) syntax. For portability reasons, an alternative way to express the above is supported:
boost::bind(boost::type<int>(), f, _1, _1)(x);
like above, the code use a boost::type for function object type,
I to know where contain the boost::type implementation?
I looked around and found the definition below.
// type.hpp
namespace boost {
// Just a simple "type envelope". Useful in various contexts, mostly to work
// around some MSVC deficiencies.
template <class T>
struct type {};
}

Any way to let the use of function pointers as template arguments easier?

I can use function pointer as template argument as the following
template<class R, class T, R (*Fun)(T)>
class MyClass;
Any way to make it is easy as
MyClass<&MyFun> a;
Here is a horrible answer, but I cannot think of a better one.
template<typename R, typename Arg, R(*Fun)(Arg)>
class MyClass {};
template<typename R, typename Arg>
struct MyClassHelper {
template<R(*Fun)(Arg)>
struct Class {
typedef MyClass<R, Arg, Fun> type;
};
};
template<typename R, typename Arg>
MyClassHelper<R, Arg> GetMyClass(R(*Fun)(Arg)); // no impl
void MyFun(int) {}
int main() {
typedef decltype( GetMyClass(&MyFun) ) A;
typedef A::Class<&MyFun> B;
typedef B::type a;
// or, in one line:
decltype( GetMyClass(&MyFun) )::Class<&MyFun>::type b;
}
which is ugly as sin. But at least it extracts the argument types of MyFun without repeating them...
It's not possible exactly as in the question, but yes it's possible if you flex your design a little bit. Let's take an example:
Suppose you have below function:
int foo (int i) { return i; }
Now you want to write:
MyClass<&foo> a; // instead of `Myclass<int, int, &foo> a;
Here how you will achieve it. First change the simple function:
int foo (int i) { return i; }
to encapsulated function object:
struct foo { // <--- function name here
int operator () (int i) { return i; } // <--- function body here
};
Both are almost same (in the case of function object an extra this pointer is passed which doesn't happen in the free function case):
int x = foo(2); // 1st case
int x = foo_(2); // 2nd case where `foo_` is an object of `struct foo`
Now you can use simply as you want!
template<class Func>
class MyClass {...}
MyClass<foo> a;
Here is a working demo.
There's already std::ptr_fun. With C++11, you can use it as
auto a = std::ptr_fun(&MyFun);
Update:
As the other attempts, and non attempts BTW, have shown, isn't it possible with your kind of template, least of all "as easy as" ;-). What you can do however, is sort of reimplement the existing standard template function pattern (std::ptr_fun, std::make_pair and the like) to return the desired type, if your main goal is "as easy as".