Perfect forwarding workaround for bit-fields - c++

I’m looking for a workaround for bit-field in overload resolution for template.
I have a function that I templated for perfect forwarding of its arguments:
template <typename... Args> void f(Args &&...args) { }
If I try to use it with a bit-field argument, like this:
struct bits { unsigned int foo:1; };
bits b{1};
f(b.foo);
…it fails to compile:
main.cpp:26:7: error: non-const reference cannot bind to bit-field 'foo'
f(b.foo);
^~~~~
Is there a way to overload f() such that it takes bit-fields by value but still takes other arguments by reference in the common case?
So far I haven't been able to. For instance, if I add an overload that takes arguments by value…
main.cpp:27:5: error: call to 'f' is ambiguous
f(b.foo);
^

http://coliru.stacked-crooked.com/view?id=b694c6cc3a52e0c14bedd6a26790d99d-e54ee7a04e4b807da0930236d4cc94dc
It can be done, if poorly. I recommend not doing this. Basically, the key part is since you can't have a pointer or a reference to a bitfield, you instead use a lambda which sets the bitfield for you.
I dislike macros as much as the next guy, but it's the only way I could think of to avoid requiring callers to put in a lambda at the callsite.
template<class assigner_type>
struct bitfieldref_type {
bitfieldref_type(bool value, assigner_type&& assign) :value(value), assign(std::move(assign)) {}
operator bool() const {return value;}
bitfieldref_type& operator=(bool v) {assign(v); value=v; return *this;}
private:
bool value;
assigner_type assign;
};
template<class assigner_type>
bitfieldref_type<assigner_type> make_bitfieldref(bool value, assigner_type&& assign)
{return {value, std::move(assign)};}
//macro is optional
#define bitfieldref(X) make_bitfieldref(X, [&](bool v)->void{X=v;})
usage:
template <class T, typename... Args> void proof_it_works(T&& first)
{first = 0;}
template <class T, typename... Args> void proof_it_works(T&& first, Args &&...args) {
first = 0;
proof_it_works(std::forward<Args>(args)...);
}
template <typename... Args> void f(Args &&...args) {proof_it_works(std::forward<Args>(args)...);}
int main() {
struct bits { unsigned int foo:1; };
bits b{1};
int a = -1;
float c = 3.14;
f(a, bitfieldref(b.foo), c);
std::cout << a << b.foo << c;
return 0;
}
I just noticed that my bitfieldref_type assumes the value is a bool, instead of a unsigned int, but I'll leave fixing that as an excersize for the user.

It cannot be done (at least not how you tried it) because the Standard says so (bold emphasis mine):
13.3.3.1.4 Reference binding [over.ics.ref]
4 Other restrictions on binding a reference to a particular argument
that are not based on the types of the reference and the argument do
not affect the formation of a standard conversion sequence, however.
[Example: a function with an “lvalue reference to int” parameter can
be a viable candidate even if the corresponding argument is an int
bit-field. The formation of implicit conversion sequences treats the
int bit-field as an int lvalue and finds an exact match with the
parameter. If the function is selected by overload resolution, the
call will nonetheless be ill-formed because of the prohibition on
binding a non-const lvalue reference to a bit-field (8.5.3). — end
example ]
This explains why
the original example fails to compile, because the reference cannot bind to a bit-field
adding an overload template<typename... Arg> f(Args.. args) gave you the ambiguity: overload resoution ended in a tie, and the reference-binding-to-bitfield prohibition never came into play.

This is the best answer I can come up with:
template <typename... Args> void f(Args &&...args) { }
struct bits { unsigned int foo:1; };
template <typename T> const T constipate(T v)
{ return(static_cast<const T>(v)); }
void bar()
{
bits b{1};
f(constipate(b.foo));
}
EDIT: There's an easier solution, that eliminates the need for the 'constipate' template:
void bar()
{
bits b{1};
f(b.foo + 0);
}

Related

How to correctly forward and use a nested tuple of constexpr struct with standard tuple operations

I want to store passed data via constexpr constructor of a struct, and store the data in a std::tuple, to perform various TMP / compile time operations.
Implementation
template <typename... _Ts>
struct myInitializer {
std::tuple<_Ts...> init_data;
constexpr myInitializer(_Ts&&... _Vs)
: init_data{ std::tuple(std::forward<_Ts>(_Vs)...) }
{}
};
Stored data uses a lightweight strong type struct, generated via lvalue and rvalue helper overload:
template <typename T, typename... Ts>
struct data_of_t {
using type = T;
using data_t = std::tuple<Ts...>;
data_t data;
constexpr data_of_t(Ts&&... _vs)
: data(std::forward<Ts>(_vs)...)
{}
};
template<typename T, typename... Ts>
constexpr auto data_of(Ts&&... _vs) {
return data_of_t<T, Ts...>(std::forward<Ts>(_vs)...);
};
template<typename T, typename... Ts>
constexpr auto data_of(Ts&... _vs) {
return data_of_t<T, Ts...>(std::forward<Ts>(_vs)...);
};
It's implemented like
template <typename T = int>
class test {
public:
static constexpr auto func(int p0=0, int p1=1, int p2=3) noexcept {
return data_of <test<T>>
(data_of<test<T>>(p0, p1));
}
};
int main() {
constexpr // fails to run constexpr // works without
auto init = myInitializer (
test<int>::func()
,test<int>::func(3)
,test<int>::func(4,5)
);
std::apply([&](auto&&... args) {
//std::cout << __PRETTY_FUNCTION__ << std::endl;
auto merged_tuple = std::tuple_cat(std::forward<decltype(args.data)>(args.data)...);
}
, init.init_data);
}
Getting to the point
std::tuple_cat fails if myInitializer instance is constexpr.
std::apply([&](auto&&... args) {
auto merged_tuple = std::tuple_cat(std::forward<decltype(args.data)>(args.data)...);
It appears to be related to the const qualifier added via constexpr.
How can this be fixed?
See full example at https://godbolt.org/z/j5xdT39aE
This:
auto merged_tuple = std::tuple_cat(std::forward<decltype(args.data)>(args.data)...);
is not the right way to forward data. decltype(args.data) is going to give you the type of that data member - which is not a function of either the const-ness or value category of args. Let's take a simpler example:
void f(auto&& arg) {
g(std::forward<decltype(arg.data)>(arg.data));
}
struct C { int data; };
C c1{1};
const C c2{2};
f(c1);
f(c2);
f(C{3});
So here I have three calls to f (which call f<C&>, f<const C&>, and f<C>, respectively). In all three cases, decltype(arg.data) is... just int. That's what the type of C::data is. But that's not how it needs to be forwarded (it won't compile for c2 because we're trying to cast away const-ness -- as in your example -- and it'll erroneously move out of c1).
What you want is to forward arg, separately, and then access data:
void f(auto&& arg) {
g(std::forward<decltype(arg)>(arg).data);
}
Now, decltype(arg) actually varies from instantiation to instantiation, which is a good indicator that we're doing something sensible.
In addition of the forwarding problem denoted by Barry, there's a different reason why you cannot have constexpr on init. This is because you contain a reference to a temporary inside data_of_t.
You see, you are containing a type obtained from overload resolution from a forwarding reference:
template<typename T, typename... Ts>
constexpr auto data_of(Ts&&... _vs) {
return data_of_t<T, Ts...>(std::forward<Ts>(_vs)...);
};
The Ts... in this case could be something like int, float const&, double&. You send those reference type and then you contain them inside of the std::tuple in data_of_t.
Those temporaries are local variables from the test function:
template <typename T = int>
class test {
public:
static constexpr auto func(int p0=0, int p1=1, int p2=3) noexcept {
return data_of <test<T>>
(data_of<test<T>>(p0, p1));
}
};
The problem here is that p0, p1, p2 are all local variable. You send them in test_of_t which will contain references to them, and you return the object containing all those reference to the local variable. This is maybe the cause of the MSVC crash. Compiler are required to provide diagnostic for any undefined behaviour in constexpr context. This crash is 100% a compiler bug and you should report it.
So how do you fix that?
Simply don't contain references by changing data_of:
template<typename T, typename... Ts>
constexpr auto data_of(Ts&&... _vs) {
return data_of_t<T, std::decay_t<Ts>...>(std::forward<Ts>(_vs)...);
};
This will decay the type thus removing the references and decay any reference to C array to pointers.
Then, you have to change your constructor. You call std::forward in there but it's no forwarding occurring if you decay in the template arguments.
template<typename... Vs> requires((std::same_as<std::decay_t<Vs>, Ts>) && ...)
constexpr data_of_t(Vs... _vs)
: data(std::forward<Vs>(_vs)...)
{}
This will add proper forwarding and also constrain it properly so it always do as data_of intended.
Just doing those change will remove UB from the code, but also change it a bit. The type data_of_t will always contain values, and won't contain references. If you want to send a reference, you will need something like std::ref, just like std::bind have to use to defer parameters.
You will still need to use std::forward<decltype(arg)>(arg).data for proper forwarding as #Barry stated

Can both a 'constexpr'-marked variable and a variable of static-storage duration allowed to be stored through a class type with a deduction guide?

Consider the following piece of code:
template <typename T>
struct wrap {
T thing;
constexpr wrap(T thing) : thing(thing) {}
};
template <typename T>
wrap(const T&) -> wrap<T>;
template <wrap V>
void fun();
struct X {
int a;
};
int main() {
constexpr auto a1 = &X::a;
static const auto a2 = &X::a;
fun<a1>();
fun<a2>(); // Doesn't compile
}
Now the thing is that one can successfully pass a1 through wrap without having to state the template parameter explicitly, but not a2 which has static-storage duration.
If I change the above deduction guide to this:
template <typename T>
wrap(const T&) -> wrap<const T&>; // <-- Note the 'const T&' here instead of plain 'T'
Then one is able to pass a2 but not a1.
If possible, how to modify the above code so that one is able to pass both a1 and a2 respectively without having to explicitly state the types like fun<wrap<decltype(a1)>{a1}>() or fun<wrap<const decltype(a2)&>{a2}>()?
Sure, it's possible. However, before I explain the solution, please allow me to suggest that you have made the problem unnecessarily difficult by insisting on a particular interface which is not (in my opinion) actually cleaner than the alternatives. Essentially, you are asking for fun<arg> to either take arg by value or by reference, depending on which one is actually well-formed. In the case of a1, it may only be taken by value; it cannot be taken by reference because it doesn't have static storage duration. In the case of a2, it cannot be taken by value because it wasn't declared constexpr, but can be taken by reference because it has static storage duration.
The code using your proposed version of fun is difficult to read, because the reader, seeing fun<arg>, does not immediately know whether arg is being taken by value or by reference. The reader must infer which one it is, based on the reader's own knowledge of whether arg is a permitted non-type template parameter by value or by reference. Furthermore, some arguments may qualify as either, and in that case the reader would also have to know which default the implementer of fun has selected for that case, in order to know what is going on.
Again, this is my opinion only: it would be much simpler if you wrote separate functions, perhaps calling them fun_val and fun_ref, where fun_val<a1>() and fun_ref<a2>() are well-formed. For this, we should define two wrapper classes, one which takes the argument by value, and one by reference:
template <typename T>
struct wrap_value {
using value_type = T;
T thing;
constexpr wrap_value(T thing) : thing(thing) {}
};
template <typename T>
wrap_value(const T&) -> wrap_value<T>;
template <typename T>
struct wrap_reference {
using value_type = T;
const T& thing;
constexpr wrap_reference(const T& thing) : thing(thing) {}
};
template <typename T>
wrap_reference(const T&) -> wrap_reference<T>;
template <wrap_value V>
void fun_val() {
std::cout << "value\n";
}
template <wrap_reference V>
void fun_ref() {
std::cout << "reference\n";
}
struct X {
int a;
};
int main() {
constexpr auto a1 = &X::a;
static const auto a2 = &X::a;
static const int x = 42;
fun_val<a1>(); // OK
fun_ref<a1>(); // Error
fun_val<a2>(); // Error
fun_ref<a2>(); // OK
fun_val<x>(); // OK; uses value of x
fun_ref<x>(); // OK; uses address of x
}
Now, if you insist on having a single name fun, then the key is to recognize that a1 and a2 have the same type, so a single application of CTAD will never be able to figure out the correct wrapper type to make the invocation well-formed. Instead, you have to use SFINAE with two overloads: the one that is invalid for the given template argument (because it takes the argument by value (resp. reference) that cannot be taken by value (resp. reference)) is discarded. Basically, rename both fun_val and fun_ref in the above example to simply fun:
template <wrap_value V>
void fun() {
std::cout << "value\n";
}
template <wrap_reference V>
void fun() {
std::cout << "reference\n";
}
This works fine in the case of a1 and a2, for which only one of the two overloads is a candidate. But in the case of x, it will be ambiguous. Let's say you want to force the by-value overload to be selected in that case. We can do that by inserting a constraint that makes the by-reference overload not a candidate:
template <wrap_reference V> requires(!requires { fun<wrap_value<typename decltype(V)::value_type>(V.thing)>(); })
void fun() {
std::cout << "reference\n";
}
You can view the full working example here.

Two function template candidates. After making one argument a reference, the less specialized template gets chosen

I have common code – Dijkstra's algorithm – I use in different contexts, so I decided to use tag dispatch.
The common code is in the following function (you can see End get dispatched depending on the Tag template parameter):
template <typename Tag, typename ... Args>
void Dijkstra(blahblah, Args&&... arg) {
...
if (End(Tag(), cost, n_id, distances, time_limit, args ...)) {
break;
}
For most of the contexts I define a default no-op as follows:
template<typename ... Args>
bool inline End(Args&& ...) {
return false;
}
For one context I define the function with the following signature:
bool inline End(OneContextTag, Duration d, NodeId n_id, Distances distances, Du time_limit, blahblah) {
Everything worked as expected, till I found I forgot & in the signature after Distances – I was copying Distances, a large unordered_map, every time.
However, after I changed it to const Distances& to avoid expensive copying, the less specialized noop version got called. I have no idea why. And how to fix it.
(I swear the change is only in adding a single character &. Or const&)
(The signature is otherwise correct, if I comment out the generic noop version, it just uses the OneContextTag version.)
(The code is more complex, but I hope it can be figured out from this.)
So what you're asking about is basically why the following program prints Special foo but Generic bar:
struct A {};
template<class ... Args>
void foo(Args&&...)
{
std::cout << "Generic foo\n";
}
void foo(A)
{
std::cout << "Special foo\n";
}
template<class ... Args>
void bar(Args&&...)
{
std::cout << "Generic bar\n";
}
void bar(A const&)
{
std::cout << "Special bar\n";
}
int main()
{
A a;
foo(a);
bar(a);
}
Let's look at what happens for overload resolution:
1. Candidate functions are selected.
C++11/[over.match.funcs]/7 In each case where a candidate is a function template, candidate function template specializations are generated using template argument deduction (14.8.3, 14.8.2). Those candidates are then handled as candidate functions in the usual way.
Candidates for call to foo(a):
template<> void foo<A&>(A&); // reference collapsing
void foo(A);
Candidates for call to bar(a):
template<> void bar<A&>(A&);
void bar(A const&);
2. Select of best viable function:
In the first place, an overload is better if (at least) one of the parameters has a better conversion sequence (and no other has a worse conversion sequence).
C++11/[over.ics.rank]/3 Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if [ ... ] S1 and S2 are reference bindings (8.5.3), and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 refers.
This results in the preference of the template candidate for bar since the conversion required to call void bar(A const&) requires binding an lvalue to an more cv-qualified const lvalue reference.
Therefore, you see the generic version called when using Distances const&.
C++11/[over.best.ics]/6 When the parameter type is not a reference [ ... ]
When the parameter has a class type and the argument expression has the same type, the implicit conversion sequence is an identity conversion.
This makes the conversion sequence for the parameter a when passed to void foo(A) an identity conversion (which is also the case for the template function).
If neither of the overloads has a better conversion sequence, then the non-template version wins over the template.
C++11/[over.match.best]/1 [ ... ] Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if [ ... ] F1 is a non-template function and F2 is a function template specialization.
This is the case for foo and makes your code behave as you intended when you use Distances distances.
I do not have an answer to why overload resolution works the way it does here atm. But I have a potential solution for you, which is also (IMO) more robust:
Change the default End to accept a UseDefaultEnd tag as the first parameter. For each context which should use the default End, subclass its tag from UseDefaultEnd:
#include <iostream>
struct UseDefaultEnd {};
/* Comment first parameter; then you get the same behavior as
you're currently trying to solve. */
template<typename ... Args>
bool inline End(UseDefaultEnd, Args&& ...) {
// bool inline End(Args&& ...) {
return false;
}
struct OneTag {};
struct OtherTag : public UseDefaultEnd {};
bool inline End(OneTag, int const & i) {
return true;
}
template<typename Tag>
void Caller() {
int i = 42;
if (End(Tag(), i)) {
std::cout << "Used specific version of End" << std::endl;
}
}
int main() {
Caller<OtherTag>();
std::cout << "---" << std::endl;
Caller<OneTag>();
}

Implicit conversion to template

My example below suggests that implicit conversions from non-template types to template types won't work as seamlessly as those only involving non-template types. Is there a way to make them work nonetheless?
Example:
struct point;
template<unsigned d> struct vec {
vec() { }
// ...
};
template<> struct vec<2> {
vec() { }
vec(const point& p) { /* ... */ } // Conversion constructor
// ...
};
struct point {
operator vec<2>() { return vec<2>(/* ... */); } // Conversion operator
};
template<unsigned d> vec<d> foo(vec<d> a, vec<d> b) {
return vec<d>(/* ... */);
}
template<unsigned d1, unsigned d2>
vec<d1 + d2> bar(vec<d1> a, vec<d2> b) {
return vec<d1 + d2>(/* ... */);
}
int main(int argc, char** argv) {
point p1, p2;
vec<2> v2;
vec<3> v3;
foo(v2, p1);
foo(p2, v2);
foo(p1, p2);
bar(v3, p1);
}
Is there a way to let this code auto-convert from point to vec<2>?
I know I can overload foo and bar to allow for point arguments, delegating to the vec implementation using an explicit conversion. But doing this for all parameter combinations will become tedious, particularly for functions with many such parameters. So I'm not interested in solutions where I have to duplicate code for every parameter combination of every function.
It appears that neither the conversion constructor nor the cast operator are sufficient to achieve this. At least my gcc 4.7.1 reports no matching function call, although it does name the desired function in a notice, stating that ‘point’ is not derived from ‘vec<d>’.
There is no direct way to get the conversion from point to vec<2>, because at the time when the function call foo(v1,p1) is processed, a function foo that expects a vec<2> as second argument does not exist yet. It's just a function template, and in order for this to be instantiated to a foo(const vec<2> &,const vec<2> &), a function call with these exact argument types would have to be given.
In order for the code to work, the compiler would have to guess both how to instantiate the template parameters, and what type the point argument to convert to. This is too much in the general case (although in your particular code it appears simple, because there is no other possible way to interpret the intent of the programmer).
In terms of solving this, the only thing I can think of is to create highly templated conversion functions:
template <typename T>
struct make_vec
{ };
template <unsigned d>
struct make_vec<vec<d>>
{
static constexpr unsigned dim = d;
using type = vec<dim>;
static const type &from(const type &v)
{ return v; }
};
template <>
struct make_vec<point>
{
static constexpr unsigned dim = 2;
using type = vec<dim>;
static type from(const point &p)
{ return type(p); }
};
template <typename T>
typename make_vec<typename std::decay<T>::type>::type make_vec_from(T&& arg)
{ return make_vec<typename std::decay<T>::type>::from(std::forward<T>(arg)); }
And then implement the foo and bar functions as general templates (accepting all kinds of types, not only vec<d>, using make_vec defined above to convert the given types to the right kind of vec<d>):
namespace detail {
/* Your original implementation of foo. */
template<unsigned d> vec<d> foo(vec<d>, vec<d>) {
return vec<d>(/* ... */);
}
}
/* Templated version of foo that calls the conversion functions (which do
nothing if the argument is already a vec<d>), and then calls the
foo() function defined above. */
template <typename T, typename... Ts>
typename make_vec<typename std::decay<T>::type>::type foo(T&& arg, Ts&&... args)
{ return detail::foo(make_vec_from(arg),make_vec_from(args)...); }
In the case of bar you also need a way to calculate the return type, which is vec<d1+d2+d3...>. For this, a sum calculator is required, also templated:
template <typename... Ts>
struct dsum {
static constexpr unsigned value = 0;
};
template <typename T, typename... Ts>
struct dsum<T,Ts...> {
static constexpr unsigned value = make_vec<typename std::decay<T>::type>::dim + dsum<Ts...>::value;
};
Then, the return type of bar() is vec<dsum<T,Ts...>::value>.
A fully working example is here: http://liveworkspace.org/code/nZJYu$11
Not exactly simple, but might be worth it if you really have extremely many different combinations of arguments.

C++11: Guaranteeing nonconverting reference from template parameter

So I have a struct X:
struct X
{
int typecode;
char* pData;
int length;
...
}
and a long list of types, we'll call this set TS. TS includes most primitive types and several class types.
For each type T in TS I have a regular function defined:
void setup(X& x, const T& t);
For example for T = string setup looks like:
void setup(X& x, const string& s)
{
x.typecode = X_STRING;
x.pData = s.c_str();
x.length = s.size();
...
}
Now I have a template function convert_to_x:
template<class T>
X convert_to_x(const T& t)
{
X x;
memset(x, 0, sizeof(x));
setup(x, t);
return x;
}
And a function f that takes an array of X:
void f(X* xs, int num_args);
And further a variadic template function g:
template<class... Args)
void g(Args... args)
{
constexpr num_args = sizeof...(args);
X xs[] = { convert_to_x(args)... };
f(xs, num_args);
}
What is going on is that you can call g with any number of parameters and types and it will convert the parameters to an array of X type, and then call f.
The problem is that if g is called with a type that is not in TS, but is convertible to a type in TS, the following happens:
A converting constructor is called to create a temporary t.
setup will store a pointer to this temporary.
the temporary is destroyed.
f is called with an xs that contains hanging pointers.
I need a way at entry to g to convert any arguments that are convertible to a type in TS but are not of a type in TS, and keep them around for the whole scope of g.
What is the best way to achieve this?
Update:
One way I just thought of that may work is to define a regular function convert for each type T in TS as follows:
T convert(const T& t) { return t; }
and then define a wrapper for g:
template<class... Args>
void g2(Args... args)
{
g(convert(args)...);
}
but I think this will cause unnecessary copying of types that are already in TS and don't need converting. Is there some way to use rvalue/lvalue semantics to avoid this?
Update 2:
Maybe this would work:
For each T in TS:
const T& convert(const T& t) { return t; }
T convert(const T&& t) { return t; }
then:
template<class... Args>
void g2(Args... args)
{
g(convert(args)...);
}
Are there any cases where setup could possibly receive a temporary with the above?
You can add deleted overloads for setup:
void setup(X& x, const string& s) = delete;
Since rvalue references bind to temporaries more readily than const lvalue references, calling setup with a temporary will select the overload with rvalue references. But since this setup overload is deleted, it would be illegal to actually call it. So when g is called with the wrong type of argument, the line X xs[] = { convert_to_x(args)... }; requires convert_to_args to call a deleted version of setup, so that instantiation fails. In turn, it causes the particular instantiation of g to fail as well.
Edit
Looking at your update #2, this should work. Since convert already causes the best conversion to one of the TS, g should never be called with unwanted types. So no temporaries would be created by unwanted conversions upon the invocation of setup. Thus, any temporaries would be arguments to g, and would be guaranteed to live for the duration of g.
Edit 2
You're right that T convert(const T&& t) { return t; } could result in values being unnecessarily copied. But this is easily fixed:
const T& convert(const T& t) { return t; }
const T&& convert(const T&& t) { return std::move(t); }
you won't get any copying of values. Lifetime of temporaries is correct, too, since temporaries live until the end of the full expression in which they are created:
template<class... Args>
void g2(Args... args)
{
g(convert(args)...);
} // ^^^^ temporaries created by a conversion here will live until g returns