diff --git a/libuavcan/dsdl_compiler/libuavcan_dsdl_compiler/data_type_template.tmpl b/libuavcan/dsdl_compiler/libuavcan_dsdl_compiler/data_type_template.tmpl index c346bd031b..7a621125f9 100644 --- a/libuavcan/dsdl_compiler/libuavcan_dsdl_compiler/data_type_template.tmpl +++ b/libuavcan/dsdl_compiler/libuavcan_dsdl_compiler/data_type_template.tmpl @@ -121,6 +121,9 @@ struct UAVCAN_EXPORT ${t.cpp_type_name} private: typename ::uavcan::StorageType< TagType >::Type _tag_; // The name is mangled to avoid clashing with fields + template + struct TagToType; + public: % endif @@ -161,61 +164,31 @@ public: % if union: /** - * Constructors and assignment operators will only work if T is unique within the union; otherwise - * compilation will fail with an error referring to ambiguous template instantiation. - */ - template - ${type_name}(const T& x) - % for idx,a in enumerate([x for x in fields if not x.void]): - ${':' if idx == 0 else ','} ${a.name}() - % endfor - % if union: - , _tag_() - % endif - { - to() = x; - } - - template - ${type_name}& operator=(const T& x) - { - to() = x; - return *this; - } - - /** - * Use explicit tag access if the union contains non-unique types. - * Otherwise it is safer to use as<>(), to<>(), is<>(). + * Explicit access to the tag. + * It is safer to use is()/as()/to() instead. */ typename Tag::Type getTag() const { return typename Tag::Type(_tag_); } void setTag(typename Tag::Type x) { _tag_ = typename ::uavcan::StorageType< TagType >::Type(x); } - /** - * Whether the union is set to the given type. - * Access by type; this will only work if the type is unique within the union; otherwise compilation will fail. - */ - template - bool is() const; - /** * Whether the union is set to the given type. * Access by tag; this will work even if there are non-unique types within the union. */ - bool is(typename Tag::Type x) const { return Tag::Type(_tag_) == x; } + bool is(typename Tag::Type x) const { return typename Tag::Type(_tag_) == x; } /** * If the union is currently set to the type T, returns pointer to the appropriate field. * If the union is set to another type, returns null pointer. */ - template - const typename ::uavcan::StorageType::Type* as() const; + template + const typename TagToType::StorageType* as() const; /** * Switches the union to the given type and returns a mutable reference to the appropriate field. - * If the previous type was different, a default constructor will be executed. + * If the previous type was different, a default constructor will be called first. */ - template - typename ::uavcan::StorageType::Type& to(); + template + typename TagToType::StorageType& to(); % endif @@ -378,54 +351,32 @@ ${generate_codec_calls_per_field(call_name='encode', self_parameter_type='Parame ${generate_codec_calls_per_field(call_name='decode', self_parameter_type='ReferenceType')} % if union: -template <> -template -typename ::uavcan::EnableIfType< typename T::StorageType, bool>::Type ${scope_prefix}<0>::is() const -{ - return is(); -} - -template <> -template -typename ::uavcan::EnableIfType< typename T::StorageType, const typename T::StorageType*>::Type -${scope_prefix}<0>::as() const -{ - return as(); -} - -template <> -template -typename ::uavcan::EnableIfType< typename T::StorageType, typename T::StorageType&>::Type -${scope_prefix}<0>::to() -{ - return to(); -} - % for idx,a in enumerate(fields): template <> template <> -bool ${scope_prefix}<0>::is< typename ::uavcan::StorageType< typename ${scope_prefix}<0>::FieldTypes::${a.name} >::Type >() const +struct ${scope_prefix}<0>::TagToType<${scope_prefix}<0>::Tag::${a.name}> { - return _tag_ == ${idx}; + typedef typename ${scope_prefix}<0>::FieldTypes::${a.name} Type; + typedef typename ::uavcan::StorageType::Type StorageType; +}; + +template <> +template <> +const typename ${scope_prefix}<0>::TagToType< ${scope_prefix}<0>::Tag::${a.name} >::StorageType* +${scope_prefix}<0>::as< ${scope_prefix}<0>::Tag::${a.name} >() const +{ + return is(${scope_prefix}<0>::Tag::${a.name}) ? &${a.name} : NULL; } template <> template <> -const typename ::uavcan::StorageType< typename ${scope_prefix}<0>::FieldTypes::${a.name} >::Type* -${scope_prefix}<0>::as< typename ::uavcan::StorageType< typename ${scope_prefix}<0>::FieldTypes::${a.name} >::Type >() const -{ - return is< typename ${scope_prefix}<0>::FieldTypes::${a.name} >() ? &${a.name} : NULL; -} - -template <> -template <> -typename ::uavcan::StorageType< typename ${scope_prefix}<0>::FieldTypes::${a.name} >::Type& -${scope_prefix}<0>::to< typename ::uavcan::StorageType< typename ${scope_prefix}<0>::FieldTypes::${a.name} >::Type >() +typename ${scope_prefix}<0>::TagToType< ${scope_prefix}<0>::Tag::${a.name} >::StorageType& +${scope_prefix}<0>::to< ${scope_prefix}<0>::Tag::${a.name} >() { if (_tag_ != ${idx}) { _tag_ = ${idx}; - ${a.name} = typename ::uavcan::StorageType< typename FieldTypes::${a.name} >::Type(); + ${a.name} = typename TagToType< ${scope_prefix}<0>::Tag::${a.name} >::StorageType(); } return ${a.name}; } diff --git a/libuavcan/include/uavcan/protocol/param_server.hpp b/libuavcan/include/uavcan/protocol/param_server.hpp index a702b5cecd..3d1395cff4 100644 --- a/libuavcan/include/uavcan/protocol/param_server.hpp +++ b/libuavcan/include/uavcan/protocol/param_server.hpp @@ -110,14 +110,14 @@ class UAVCAN_EXPORT ParamServer } // Assign if needed, read back - if (!in.value.is()) + if (!in.value.is(protocol::param::Value::Tag::empty)) { manager_->assignParamValue(out.name, in.value); } manager_->readParamValue(out.name, out.value); // Check if the value is OK, otherwise reset the name to indicate that we have no idea what is it all about - if (!out.value.is()) + if (!out.value.is(protocol::param::Value::Tag::empty)) { manager_->readParamDefaultMaxMin(out.name, out.default_value, out.max_value, out.min_value); } diff --git a/libuavcan/test/protocol/param_server.cpp b/libuavcan/test/protocol/param_server.cpp index a949cb3422..fe8fe8837f 100644 --- a/libuavcan/test/protocol/param_server.cpp +++ b/libuavcan/test/protocol/param_server.cpp @@ -32,22 +32,22 @@ struct ParamServerTestManager : public uavcan::IParamManager KeyValue::iterator it = kv.find(name.c_str()); if (it != kv.end()) { - if (value.is()) + if (value.is(Value::Tag::boolean_value)) { assert(value.getTag() == Value::Tag::boolean_value); it->second = double(value.boolean_value); } - else if (value.is()) + else if (value.is(Value::Tag::integer_value)) { assert(value.getTag() == Value::Tag::integer_value); it->second = double(value.integer_value); } - else if (value.is()) + else if (value.is(Value::Tag::real_value)) { assert(value.getTag() == Value::Tag::real_value); it->second = double(value.real_value); } - else if (value.is()) + else if (value.is(Value::Tag::string_value)) { assert(value.getTag() == Value::Tag::string_value); it->second = std::atof(value.string_value.c_str()); @@ -65,7 +65,7 @@ struct ParamServerTestManager : public uavcan::IParamManager KeyValue::const_iterator it = kv.find(name.c_str()); if (it != kv.end()) { - out_value = float(it->second); + out_value.to() = float(it->second); assert(out_value.getTag() == Value::Tag::real_value); } std::cout << "READ [" << name.c_str() << "]\n" << out_value << "\n---" << std::endl; @@ -141,10 +141,10 @@ TEST(ParamServer, Basic) // No such variable, shall return empty name/value get_set_rq.index = 0; get_set_rq.name.clear(); - get_set_rq.value = uavcan::int64_t(0xDEADBEEF); + get_set_rq.value.to() = 0xDEADBEEF; doCall(get_set_cln, get_set_rq, nodes); ASSERT_TRUE(get_set_cln.collector.result->getResponse().name.empty()); - ASSERT_TRUE(get_set_cln.collector.result->getResponse().value.is()); + ASSERT_TRUE(get_set_cln.collector.result->getResponse().value.is(uavcan::protocol::param::Value::Tag::empty)); mgr.kv["foobar"] = 123.456; // New param @@ -153,21 +153,24 @@ TEST(ParamServer, Basic) get_set_rq.name = "foobar"; doCall(get_set_cln, get_set_rq, nodes); ASSERT_STREQ("foobar", get_set_cln.collector.result->getResponse().name.c_str()); - ASSERT_TRUE(get_set_cln.collector.result->getResponse().value.is()); - ASSERT_FLOAT_EQ(123.456F, get_set_cln.collector.result->getResponse().value.to()); + ASSERT_TRUE(get_set_cln.collector.result->getResponse().value.is(uavcan::protocol::param::Value::Tag::real_value)); + ASSERT_FLOAT_EQ(123.456F, get_set_cln.collector.result->getResponse().value. + to()); // Set by index get_set_rq = uavcan::protocol::param::GetSet::Request(); get_set_rq.index = 0; - get_set_rq.value = uavcan::protocol::param::Value::FieldTypes::string_value("424242"); + get_set_rq.value.to() = "424242"; doCall(get_set_cln, get_set_rq, nodes); ASSERT_STREQ("foobar", get_set_cln.collector.result->getResponse().name.c_str()); - ASSERT_FLOAT_EQ(424242, get_set_cln.collector.result->getResponse().value.to()); + ASSERT_FLOAT_EQ(424242, get_set_cln.collector.result->getResponse().value. + to()); // Get by index get_set_rq = uavcan::protocol::param::GetSet::Request(); get_set_rq.index = 0; doCall(get_set_cln, get_set_rq, nodes); ASSERT_STREQ("foobar", get_set_cln.collector.result->getResponse().name.c_str()); - ASSERT_FLOAT_EQ(424242, get_set_cln.collector.result->getResponse().value.to()); + ASSERT_FLOAT_EQ(424242, get_set_cln.collector.result->getResponse().value. + to()); } diff --git a/libuavcan_drivers/linux/apps/uavcan_nodetool.cpp b/libuavcan_drivers/linux/apps/uavcan_nodetool.cpp index 78a3e44cad..7bd06584f5 100644 --- a/libuavcan_drivers/linux/apps/uavcan_nodetool.cpp +++ b/libuavcan_drivers/linux/apps/uavcan_nodetool.cpp @@ -76,19 +76,19 @@ public: std::string paramValueToString(const uavcan::protocol::param::Value& value) { - if (auto x = value.as()) + if (auto x = value.as()) { return *x ? "true" : "false"; } - if (auto x = value.as()) + if (auto x = value.as()) { return std::to_string(*x); } - if (auto x = value.as()) + if (auto x = value.as()) { return std::to_string(*x); } - if (auto x = value.as()) + if (auto x = value.as()) { return std::string(x->c_str()) + " "; } @@ -97,11 +97,11 @@ std::string paramValueToString(const uavcan::protocol::param::Value& value) std::string paramValueToString(const uavcan::protocol::param::NumericValue& value) { - if (auto x = value.as()) + if (auto x = value.as()) { return std::to_string(*x); } - if (auto x = value.as()) + if (auto x = value.as()) { return std::to_string(*x); } @@ -191,7 +191,7 @@ const std::map() = std::stof(args.at(1)); printGetSetResponse(call(*client, node_id, request)); } }