Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

value.set(T&&) is problematic #147

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

value.set(T&&) is problematic #147

wants to merge 2 commits into from

Conversation

cuzdav
Copy link

@cuzdav cuzdav commented Mar 20, 2022

This fixes an issue where we cannot call myValue.set(1.5) or double d=1.5; myValue.set(d); because both versions fail to link. They both match the forwarding reference set(T&&) function better than the expected set(T const&) version, and it is not defined for several types. Problems occur with double, bool, int64, and std::string. The problem with std::string is only with lvalues, in that the "non-const to const" conversion makes the set(std::string const&) a worse match than the rvalue forwardig reference, which was not defined.

I changed the forwarding reference from a template to three explicit function declarations, so we don't have such a large set of interfaces inadvertently caught by the template.

I also ran clang-format in another commit, prior to making the change, since the code did not match its own .clang-format file format.

The changes in the tests will show the link failures mentioned in the commit message, if run with the original picojson header, but it passes after my changes.

undefined reference to `void picojson::value::set<bool>(bool&&)'
undefined reference to `void picojson::value::set<bool&>(bool&)'
undefined reference to `void picojson::value::set<bool>(bool&&)'
undefined reference to `void picojson::value::set<bool&>(bool&)'
undefined reference to `void picojson::value::set<double>(double&&)'
undefined reference to `void picojson::value::set<double&>(double&)'
undefined reference to `void picojson::value::set<double>(double&&)'
undefined reference to `void picojson::value::set<double&>(double&)'
undefined reference to `void picojson::value::set<std::string&>(std::string&)'

The issue with std::string& is that an lvalue

The rvalue reference conditional was implemented with a
universal/forwarding reference.  This has problems:

Updated tests to do additional checks.  Added calls to set() with an
rvalue and (nonconst) lvalue version of 'cmp', which caused the following
link errors in the original picojson code:

undefined reference to `void picojson::value::set<bool>(bool&&)'
undefined reference to `void picojson::value::set<bool&>(bool&)'
undefined reference to `void picojson::value::set<bool>(bool&&)'
undefined reference to `void picojson::value::set<bool&>(bool&)'
undefined reference to `void picojson::value::set<double>(double&&)'
undefined reference to `void picojson::value::set<double&>(double&)'
undefined reference to `void picojson::value::set<double>(double&&)'
undefined reference to `void picojson::value::set<double&>(double&)'
undefined reference to `void picojson::value::set<std::string&>(std::string&)'

Afterwards all tests pass.

The problem is the definition of the template `set(T&&)` function,
which (due to being a forwarding reference) is a better match than the
set(T const&) versions when passing an rvalue or a non-const lvalue
(since it can be an exact match, while the T const& version must
undero a const-conversion).

The change in picojson is to remove the set(T&&) template and provide
the 3 explicit overloads for the rvalue-reference types intended
(where moving makes sense).  Now it stops matching the other types
that were not intended.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant