I'm getting this compilation error with the following code
#include <iostream>
#include <boost/optional.hpp>
#include "nlohmann_json.hpp"
namespace nlohmann {
template <typename T>
struct adl_serializer<boost::optional<T>> {
static void to_json(json& j, const boost::optional<T>& opt) {
if (opt == boost::none) j = nullptr;
else j = *opt;
}
static void from_json(const json& j, boost::optional<T>& opt) {
if (j.is_null()) opt = boost::none;
else opt = j.get<T>();
}
};
}
int main(int argc, char* argv[]) {
nlohmann::json json;
boost::optional<std::string> str = json["str"]; // works
// boost::optional<std::string> str;
// str = json["str"]; // doesn't work
}
The full error message is
nlohmann.cc: In function 'int main(int, char**)':
nlohmann.cc:24:19: error: ambiguous overload for 'operator=' (operand types are 'boost::optional<std::__cxx11::basic_string<char> >' and 'nlohmann::basic_json<>::value_type {aka nlohmann::basic_json<>}')
str = json["str"];
^
In file included from /opt/gcc-7.2.0/include/boost/optional.hpp:15:0,
from nlohmann.cc:2:
/opt/gcc-7.2.0/include/boost/optional/optional.hpp:1019:15: note: candidate: boost::optional<T>& boost::optional<T>::operator=(const boost::optional<T>&) [with T = std::__cxx11::basic_string<char>]
optional& operator= ( optional const& rhs ) = default;
^~~~~~~~
/opt/gcc-7.2.0/include/boost/optional/optional.hpp:1031:15: note: candidate: boost::optional<T>& boost::optional<T>::operator=(boost::optional<T>&&) [with T = std::__cxx11::basic_string<char>]
optional& operator= ( optional && ) = default;
^~~~~~~~
/opt/gcc-7.2.0/include/boost/optional/optional.hpp:1078:15: note: candidate: boost::optional<T>& boost::optional<T>::operator=(boost::none_t) [with T = std::__cxx11::basic_string<char>]
optional& operator= ( none_t none_ ) BOOST_NOEXCEPT
What is the difference between the two assignment operator use cases? Why does the second one not work?
I'm using GCC 7.2.0, with -std=c++14.
Related
So I have the following struct:
struct Snowflake {
Snowflake() : _value(0) {}
Snowflake(uint64_t value) : _value(value) {}
Snowflake(std::string value) : _value(std::stoull(value)) {}
Snowflake(const Snowflake &) = default;
operator uint64_t &() { return _value; }
operator uint64_t() const { return _value; }
operator std::string() const { return std::to_string(_value); }
Snowflake &operator=(uint64_t val) {
_value = val;
return *this;
}
Snowflake &operator=(const std::string &str) {
_value = std::stoull(str);
return *this;
}
Snowflake &operator=(const Snowflake &s) {
_value = s._value;
return *this;
}
protected:
uint64_t _value;
};
If I declare Snowflake snowflake = 336227221100429313; then I can use fmt::print("Snowflake: {}", snowflake); for example just fine but I can't use std::vector<Snowflake> snowflakes{164234463247597568, 106615803402547200, 268487751370801152}; with fmt::print("Snowflakes: {}", snowflakes); I get the following error:
In file included from -snip-/cmake-build-debug/_deps/fmt-src/include/fmt/format.h:48,
from -snip-/snowflake.hh:8,
from -snip-/main.cpp:2:
-snip-/cmake-build-debug/_deps/fmt-src/include/fmt/core.h: In instantiation of ‘constexpr fmt::v8::detail::value<Context> fmt::v8::detail::make_arg(T&&) [with bool IS_PACKED = true; Context = fmt::v8::basic_format_context<fmt::v8::appender, char>; fmt::v8::detail::type <anonymous> = fmt::v8::detail::type::custom_type; T = std::vector<Snowflake>&; typename std::enable_if<IS_PACKED, int>::type <anonymous> = 0]’:
-snip-/cmake-build-debug/_deps/fmt-src/include/fmt/core.h:1807:77: required from ‘constexpr fmt::v8::format_arg_store<Context, Args>::format_arg_store(T&& ...) [with T = {std::vector<Snowflake, std::allocator<Snowflake> >&}; Context = fmt::v8::basic_format_context<fmt::v8::appender, char>; Args = {std::vector<Snowflake, std::allocator<Snowflake> >}]’
-snip-/cmake-build-debug/_deps/fmt-src/include/fmt/core.h:1824:38: required from ‘constexpr fmt::v8::format_arg_store<Context, fmt::v8::remove_cvref_t<Args>...> fmt::v8::make_format_args(Args&& ...) [with Context = fmt::v8::basic_format_context<fmt::v8::appender, char>; Args = {std::vector<Snowflake, std::allocator<Snowflake> >&}]’
-snip-/cmake-build-debug/_deps/fmt-src/include/fmt/core.h:3156:44: required from ‘void fmt::v8::print(fmt::v8::format_string<T ...>, T&& ...) [with T = {std::vector<Snowflake, std::allocator<Snowflake> >&}; fmt::v8::format_string<T ...> = fmt::v8::basic_format_string<char, std::vector<Snowflake, std::allocator<Snowflake> >&>]’
-snip-/main.cpp:10:44: required from here
-snip-/cmake-build-debug/_deps/fmt-src/include/fmt/core.h:1680:7: error: static assertion failed: Cannot format an argument. To make type T formattable provide a formatter<T> specialization: https://fmt.dev/latest/api.html#udt
1680 | formattable,
| ^~~~~~~~~~~
I tried declaring the following:
template <> struct fmt::formatter<Snowflake> : formatter<uint64_t> {
template <typename FormatContext>
auto format(Snowflake s, FormatContext &ctx) {
return formatter<uint64_t>::format(s, ctx);
}
};
but that hasn't solved the issue. Do I need to celare a fmt::formatter for std::vector<Snowflake>? What would be the easiest way to do that?
It works in the current version of {fmt} (https://godbolt.org/z/98qzcb8r9):
#include <fmt/ranges.h>
...
auto snowflake = Snowflake(336227221100429313);
fmt::print("Snowflake: {}\n", snowflake);
auto snowflakes = std::vector<Snowflake>{164234463247597568, 106615803402547200, 268487751370801152};
fmt::print("{}\n", snowflakes);
prints
Snowflake: 336227221100429313
[164234463247597568, 106615803402547200, 268487751370801152]
Relying on implicit conversion is not recommended though.
So here is the scenario I have been to trying to work upon
#include <iostream>
#include <vector>
#include <string>
#include <complex>
class Double
{
private:
double dd;
std::vector<double> gg;
std::string ss;
public:
Double(double d,const std::string& s = std::string())
{
dd = d;
ss = s;
gg = std::vector<double>();
}
Double(const std::vector<double>& d,const std::string& s = std::string())
{
dd = 0;
ss = s;
gg = d;
}
double getdd() const { return dd; }
};
template<typename T>
Double getDouble(T t,const std::string& s = std::string())
{
return Double(t,s);
}
std::string to_string(Double d)
{
double zd = d.getdd() + 1.0;
return std::to_string(zd);
}
class TEST
{
public:
template<typename T_0>
TEST(const T_0 & var_0)
{
auto x = to_string(getDouble(var_0));
}
};
int main()
{
TEST ds ({3.4,"ssd"});
std::cout << "Reached heare\n";
return 0;
}
Essentially if I call
Double dd ({3.4,"ssd"});
everything works fine but if I try the same thing with the class TEST, I get the following error.
main.cpp: In function 'int main()':
main.cpp:57:25: error: no matching function for call to 'TEST::TEST(<brace-enclosed initializer list>)'
TEST ds ({3.4,"ssd"});
^
main.cpp:48:5: note: candidate: template<class T_0> TEST::TEST(const T_0&)
TEST(const T_0 & var_0)
^
main.cpp:48:5: note: template argument deduction/substitution failed:
main.cpp:57:25: note: couldn't deduce template parameter 'T_0'
TEST ds ({3.4,"ssd"});
^
main.cpp:44:8: note: candidate: constexpr TEST::TEST(const TEST&)
class TEST
^
main.cpp:44:8: note: no known conversion for argument 1 from '<brace-enclosed initializer list>' to 'const TEST&'
main.cpp:44:8: note: candidate: constexpr TEST::TEST(TEST&&)
main.cpp:44:8: note: no known conversion for argument 1 from '<brace-enclosed initializer list>' to 'TEST&&'
I have tried to deduce the parameters adding a constructor as below
Double (std::initializer_list<boost::any> xx)
but it hasnt worked for me.
Is there any way to get past this issue ? I cant use the explicit type at the callsite since the elements of the initializer list are not of the same type.
Unfortunately the braced-init-list doesn't have any type; the template parameter T_0 can't be deduced from it.
You can use parameter pack instead.
template<typename... T_0>
TEST(const T_0 & ... var_0)
{
auto x = to_string(getDouble(var_0...));
}
then use it like
TEST ds (3.4,"ssd");
LIVE
This call works
Double dd ({3.4,"ssd"});
because there is appropriate constructor
Double(double d,const std::string& s = std::string())
{
dd = d;
ss = s;
gg = std::vector<double>();
}
This call
TEST ds ({3.4,"ssd"});
does not work because the template constructor has only one parameter
template<typename T_0>
TEST(const T_0 & var_0)
{
auto x = to_string(getDouble(var_0));
}
Pay attention to that this construction {3.4,"ssd"} does not have a type. SO the compiler reports that
main.cpp:48:5: note: template argument deduction/substitution failed:
main.cpp:57:25: note: couldn't deduce template parameter 'T_0'
TEST ds ({3.4,"ssd"});
^
I have a simple primitive type wrapper:
template <typename T>
class Scalar {
public:
explicit Scalar(T value) : value{value} {}
Scalar(Scalar&& other) = default;
Scalar& operator=(Scalar&& other) = default;
Scalar(const Scalar& other) = default;
Scalar& operator=(const Scalar& other) = default;
template <typename U>
explicit operator Scalar<U>() {
return Scalar<U>{static_cast<U>(this->value)};
}
inline T getValue() const noexcept { return this->value; }
private:
T value;
};
Casting Scalar values works well, but somehow it fails for references, e.g.
auto a = Scalar<double>{2.54};
Scalar<int> b = static_cast<Scalar<int>>(a); // works
const auto& c = a;
Scalar<int> d = static_cast<Scalar<int>>(c); // fails
Here's the compilation error (can be checked here http://rextester.com/GOPYU13091), any ideas what might be the issue here?
source_file.cpp: In function ‘int main()’:
source_file.cpp:31:47: error: no matching function for call to ‘Scalar(const Scalar<double>&)’
Scalar<int> d = static_cast<Scalar<int>>(c);
^
source_file.cpp:12:3: note: candidate: Scalar<T>::Scalar(const Scalar<T>&) [with T = int] <near match>
Scalar(const Scalar& other) = default;
^
source_file.cpp:12:3: note: conversion of argument 1 would be ill-formed:
source_file.cpp:31:47: error: could not convert ‘c’ from ‘const Scalar<double>’ to ‘const Scalar<int>&’
Scalar<int> d = static_cast<Scalar<int>>(c);
^
source_file.cpp:10:3: note: candidate: Scalar<T>::Scalar(Scalar<T>&&) [with T = int] <near match>
Scalar(Scalar&& other) = default;
^
source_file.cpp:10:3: note: conversion of argument 1 would be ill-formed:
source_file.cpp:31:47: error: could not convert ‘c’ from ‘const Scalar<double>’ to ‘Scalar<int>&&’
Scalar<int> d = static_cast<Scalar<int>>(c);
^
This is a const vs non-const issue, not a reference vs object issue.
Using
auto& c = a;
Scalar<int> d = static_cast<Scalar<int>>(c);
works for me.
By changing the user defined conversion operator to const member function
template <typename U>
explicit operator Scalar<U>() const {
return Scalar<U>{static_cast<U>(this->value)};
}
also makes sure that the following works.
const auto& c = a;
Scalar<int> d = static_cast<Scalar<int>>(c);
Consider the following code:
#include <unordered_map>
#include <tuple>
namespace Test
{
template<typename State>
struct StateTableEntry
{
State state;
};
template<typename State>
using StateRow = std::unordered_map<int,StateTableEntry<State>>;
template<typename StateRowValueType>
auto& entryBAD(StateRowValueType& row)
{ return row.second; }
template<typename StateRowValueType>
auto entryOK(StateRowValueType& row) -> decltype((row.second))
{ return row.second; }
}
template<class T,int I,class O> std::enable_if_t<I==std::tuple_size<T>::value>
for_each_index_of(O&){}
template<class Tuple, int startingIndex=0, class Operation>
std::enable_if_t<startingIndex<std::tuple_size<Tuple>::value>
for_each_index_of(const Operation& operation)
{
operation(std::integral_constant<std::size_t,startingIndex>());
for_each_index_of<Tuple,startingIndex+1>(operation);
}
int main()
{
for_each_index_of<std::tuple<int>>([](const auto&)
{
Test::StateRow<long> stateRow;
for(auto& rowElement : stateRow)
{
auto& state(entryBAD(rowElement).state);
state=1;
}
});
}
If I try to compile it as is, gcc tells me
test.cpp: In instantiation of ‘main()::<lambda(const auto:1&)> [with auto:1 = std::integral_constant<long unsigned int, 0ul>]’:
test.cpp:29:14: required from ‘std::enable_if_t<(startingIndex < std::tuple_size<_Tp>::value)> for_each_index_of(const Operation&) [with Tuple = std::tuple<int>; int startingIndex = 0; Operation = main()::<lambda(const auto:1&)>; std::enable_if_t<(startingIndex < std::tuple_size<_Tp>::value)> = void]’
test.cpp:43:6: required from here
test.cpp:40:44: error: use of ‘template<class StateRowValueType> auto& Test::entryBAD(StateRowValueType&)’ before deduction of ‘auto’
auto& state(entryBAD(rowElement).state);
^
test.cpp:40:44: error: use of ‘auto& Test::entryBAD(StateRowValueType&) [with StateRowValueType = std::pair<const int, Test::StateTableEntry<long int> >]’ before deduction of ‘auto’
test.cpp:24:1: error: ‘std::enable_if_t<(I == std::tuple_size<_Tp>::value)> for_each_index_of(O&) [with T = std::tuple<int>; int I = 1; O = const main()::<lambda(const auto:1&)>; std::enable_if_t<(I == std::tuple_size<_Tp>::value)> = void]’, declared using local type ‘const main()::<lambda(const auto:1&)>’, is used but never defined [-fpermissive]
for_each_index_of(O&){}
^
But if I move the conde of lambda out of the lambda or replace call of entryBAD with entryOK, for some reason compilation succeeds. Same success if I move definition of entryBAD out of namespace Test.
Also, clang++ 3.6 compiles in all cases without complaints.
Is gcc right or is it a bug in it? If gcc is right, then what's wrong with the code?
I can't figure out what is ambiguous about swap(arr[i++],arr[n--]); below. Please educate me on my wrongful ways.
#include <iostream>
#include <string>
template <typename T> void swap ( T & a, T & b )
{
T temp = b;
b = a;
a = temp;
}
template <typename T> void reverse_array ( T * arr, size_t n )
{
size_t i = 0;
while (i < n) swap(arr[i++],arr[n--]); // problem line
}
int main ()
{
char mystr [] = "Obama smokes";
reverse_array(mystr, sizeof(mystr)/sizeof(char));
return 0;
}
codepad has an implicit using namespace std;, which is a really bad idea and makes your swap conflict with std::swap. You can use ::swap instead, but not before fixing your bounds problem by passing sizeof mystr - 2 instead of sizeof(mystr)/sizeof(char).
As #minitech mentions in his answer, the problem is because of the implicit namespace declaration, e.g. using namespace std;
With that I get the following error, which shows that the conflict is with std::swap:
100%] Building CXX object CMakeFiles/csi_projects.dir/main.cpp.o
/home/vsnyc/ClionProjects/main.cpp: In instantiation of ‘void reverse_array(T*, size_t) [with T = char; size_t = long unsigned int]’:
/home/vsnyc/ClionProjects/main.cpp:151:52: required from here
/home/vsnyc/ClionProjects/main.cpp:144:43: error: call of overloaded ‘swap(char&, char&)’ is ambiguous
while (i < n) { swap(arr[i++],arr[n--]); } // problem line
^
/home/vsnyc/ClionProjects/main.cpp:144:43: note: candidates are:
/home/vsnyc/ClionProjects/main.cpp:134:28: note: void swap(T&, T&) [with T = char]
template <typename T> void swap ( T & a, T & b )
^
In file included from /usr/include/c++/4.8/bits/stl_pair.h:59:0,
from /usr/include/c++/4.8/bits/stl_algobase.h:64,
from /usr/include/c++/4.8/bits/char_traits.h:39,
from /usr/include/c++/4.8/ios:40,
from /usr/include/c++/4.8/ostream:38,
from /usr/include/c++/4.8/iostream:39,
from /home/vsnyc/ClionProjects/main.cpp:1:
/usr/include/c++/4.8/bits/move.h:166:5: note: void std::swap(_Tp&, _Tp&) [with _Tp = char]
swap(_Tp& __a, _Tp& __b)
^