Repository: eclipse-iceoryx/iceoryx (C++)

Issue:
Can't directly assign `const` underlying value to `iox::optional`
## Required information

**Operating system:**
Ubuntu 20.04.6 LTS

**Compiler version:**
Clang 11, GCC 9.4.0

**Eclipse iceoryx version:**
`master`

**Observed result or behaviour:**
In the implementation of `iox::optional::operator=` for direct assignment of the underlying value, the `newValue` parameter is forwarded as `T` instead of `U`, which results in a build error when attempting to assign a `const` value.  This can be fixed by changing the two instances of `std::forward<T>` to `std::forward<U>`.

https://github.com/eclipse-iceoryx/iceoryx/blob/1e17b23d50e7ac2243f43969d90e7f5e8b60afca/iceoryx_hoofs/vocabulary/include/iox/detail/optional.inl#L164-L179


**Expected result or behaviour:**
No build error.

**Conditions where it occurred / Performed steps:**

I was able to replicate the error in the `test_vocabulary_optional.cpp` test by adding the following cases:
```
TEST_F(Optional_test, DirectCopyAssignmentWithNoValue)
{
    ::testing::Test::RecordProperty("TEST_ID", "8dddd1c5-e59b-4f3c-9e6c-6fa9ac1daa86");
    iox::optional<TestClass> sut;
    const TestClass value{4711, 1337};

    sut = value;
    ASSERT_THAT(sut.has_value(), Eq(true));
    EXPECT_THAT(sut->value, Eq(4711));
    EXPECT_THAT(sut->secondValue, Eq(1337));
}

TEST_F(Optional_test, DirectCopyAssignmentWithValue)
{
    ::testing::Test::RecordProperty("TEST_ID", "66fa19ab-0a08-48d3-824c-7b259e6f15b0");
    iox::optional<TestClass> sut{TestClass{7474, 33331}};
    const TestClass value{4711, 1337};

    sut = value;
    ASSERT_THAT(sut.has_value(), Eq(true));
    EXPECT_THAT(sut->value, Eq(4711));
    EXPECT_THAT(sut->secondValue, Eq(1337));
}
```
The error occurs when the `TestCase value` is `const` or `constexpr` qualified.

```
iceoryx_hoofs/vocabulary/include/iox/detail/optional.inl:172:34: error: binding reference of type 'std::remove_reference<{anonymous}::Optional_test::TestClass>::type&' {aka '{anonymous}::Optional_test::TestClass&'} to 'const {anonymous}::Optional_test::TestClass' discards qualifiers
  172 |         value() = std::forward<T>(newValue);
      |                   ~~~~~~~~~~~~~~~^~~~~~~~~~

iceoryx_hoofs/vocabulary/include/iox/detail/optional.inl:176:40: error: binding reference of type 'std::remove_reference<{anonymous}::Optional_test::TestClass>::type&' {aka '{anonymous}::Optional_test::TestClass&'} to 'const {anonymous}::Optional_test::TestClass' discards qualifiers
  176 |         construct_value(std::forward<T>(newValue));
      |                         ~~~~~~~~~~~~~~~^~~~~~~~~~
```


Discussion: @tdouglas-latai Thanks for the bug report.

Since you essentially also fixed the problem do you want to create a pull request, and we merge it, otherwise I would take it over and fix it.
Sure, I can put up a PR



Fix (patch):
diff --git a/doc/website/release-notes/iceoryx-unreleased.md b/doc/website/release-notes/iceoryx-unreleased.md
index 332c26e31f..96e4ab6d9e 100644
--- a/doc/website/release-notes/iceoryx-unreleased.md
+++ b/doc/website/release-notes/iceoryx-unreleased.md
@@ -125,6 +125,7 @@
 - Fix wrong memory orders in SpscFiFo [#2167](https://github.com/eclipse-iceoryx/iceoryx/issues/2167)
 - Implement missing copy assignment for expected [#2216](https://github.com/eclipse-iceoryx/iceoryx/issues/2216)
 - Add missing type aliases that conform with STL container types [#2220](https://github.com/eclipse-iceoryx/iceoryx/issues/2220)
+- Fix `const` value assignment in `iox::optional` [\#2224](https://github.com/eclipse-iceoryx/iceoryx/issues/2224)
 
 **Refactoring:**
 
diff --git a/iceoryx_hoofs/vocabulary/include/iox/detail/optional.inl b/iceoryx_hoofs/vocabulary/include/iox/detail/optional.inl
index 309abee25f..71cc5f4592 100644
--- a/iceoryx_hoofs/vocabulary/include/iox/detail/optional.inl
+++ b/iceoryx_hoofs/vocabulary/include/iox/detail/optional.inl
@@ -169,11 +169,11 @@ optional<T>::operator=(U&& newValue) noexcept
 {
     if (m_hasValue)
     {
-        value() = std::forward<T>(newValue);
+        value() = std::forward<U>(newValue);
     }
     else
     {
-        construct_value(std::forward<T>(newValue));
+        construct_value(std::forward<U>(newValue));
     }
     return *this;
 }
diff --git a/tools/introspection/source/introspection_app.cpp b/tools/introspection/source/introspection_app.cpp
index da1e809528..ab1ed02ef9 100644
--- a/tools/introspection/source/introspection_app.cpp
+++ b/tools/introspection/source/introspection_app.cpp
@@ -793,7 +793,7 @@ void IntrospectionApp::runIntrospection(const iox::units::Duration updatePeriod,
         {
             prettyPrint("### MemPool Status ###\n\n", PrettyOptions::highlight);
 
-            memPoolSubscriber->take().and_then([&](auto& sample) { memPoolSample = sample; });
+            memPoolSubscriber->take().and_then([&](auto& sample) { memPoolSample = std::move(sample); });
 
             if (memPoolSample)
             {
@@ -812,7 +812,7 @@ void IntrospectionApp::runIntrospection(const iox::units::Duration updatePeriod,
         if (introspectionSelection.process == true)
         {
             prettyPrint("### Processes ###\n\n", PrettyOptions::highlight);
-            processSubscriber->take().and_then([&](auto& sample) { processSample = sample; });
+            processSubscriber->take().and_then([&](auto& sample) { processSample = std::move(sample); });
 
             if (processSample)
             {
@@ -827,12 +827,12 @@ void IntrospectionApp::runIntrospection(const iox::units::Duration updatePeriod,
         // print port information
         if (introspectionSelection.port == true)
         {
-            portSubscriber->take().and_then([&](auto& sample) { portSample = sample; });
+            portSubscriber->take().and_then([&](auto& sample) { portSample = std::move(sample); });
 
-            portThroughputSubscriber->take().and_then([&](auto& sample) { portThroughputSample = sample; });
+            portThroughputSubscriber->take().and_then([&](auto& sample) { portThroughputSample = std::move(sample); });
 
             subscriberPortChangingDataSubscriber->take().and_then(
-                [&](auto& sample) { subscriberPortChangingDataSamples = sample; });
+                [&](auto& sample) { subscriberPortChangingDataSamples = std::move(sample); });
 
             if (portSample && portThroughputSample && subscriberPortChangingDataSamples)
             {