user3932876
user3932876

Reputation: 267

C++ set value if member exists

template<typename T>
if (std::is_same<T, FrontCameraSegment>::value) {
    height = segment.height;
}

I have a template to process several sensors. One sends me a height property, the others do not. I need that value once in my code, the rest of the Visualize() function is the same for every sensor. So I wanted to check whether T is_same with FrontCameraSegment and then I wanted to use the segment.height property once. However, the compiler says that "height" is not a member of all elements passed to T which is logic. Casts don't work because of the same reason. Restructuring the sensors using inheritance is not possible (I am not allowed to do that part).

So my question: How can I tell the compiler that I checked that height is a member?

Upvotes: 1

Views: 638

Answers (2)

Jarod42
Jarod42

Reputation: 217293

In C++17, you could use constexpr if:

template<typename T>
void foo(T& segment)
{
    if constexpr (std::is_same<T, FrontCameraSegment>::value) {
       height = segment.height;
    }
    // ...
}

Before, you have to use some specialization/dispatching:

// fallback
template<typename T>
void setHeightIfPossible(float& height, const T& segment) { /* Empty */ }

void setHeightIfPossible(float& height, const FrontCameraSegment& segment) {
    height = segment.height;
}

template<typename T>
void foo(T& segment)
{
    // ...
    setHeightIfPossible(height, segment);
    // ...
}

Upvotes: 3

Richard Hodges
Richard Hodges

Reputation: 69882

use a enable-if-style functor to optionally apply the height, for example:

#include <utility>
#include <iostream>

namespace notstd {
    template<typename... Ts> struct make_void { typedef void type;};
    template<typename... Ts> using void_t = typename make_void<Ts...>::type;
}
struct Sensor1
{
    int width;
};

struct Sensor2
{
    int width;
    int height;
};

template<class Sensor, typename = void>
struct height_reader
{
    template<class SensorArg>
    void operator()(SensorArg&& source, int& target) const
    {
        // no-op
    }
};

template<class Sensor>
struct height_reader<Sensor, 
    notstd::void_t<decltype(std::declval<Sensor>().height)>> 
{
    template<class SensorArg>
    void operator()(SensorArg&& source, int& target) const
    {
        target = source.height;
    }
};


struct Readings
{
    int width = 0, height = 0;
    template<class Sensor> void apply_sensor(Sensor&& sensor)
    {  
        width = sensor.width;
        height_reader<Sensor> hr;
        hr(sensor, height);
    }

};

void emit(int i)
{
    std::cout << i << std::endl;
}

int main()
{
    Sensor1 s1 { 1 };
    Sensor2 s2 { 2, 3 };

    Readings r;
    r.apply_sensor(s1);
    r.apply_sensor(s2);
    emit(r.height);
}

Upvotes: 0

Related Questions