0

I would like to have a templated function like so:

template <typename T>
void ReadHelper(T vector_array[])
{
    // some code
}

Where T is some structure. But there are two different versions of this structure:

struct type1 {
    float data;
}

struct type2 {
    float data;
    bool valid;
}

And I would like for ReadHelper to be able to set that valid flag. What is a good way to write two different templated functions to properly handle the two types of structures? I can certainly write overloaded version for all my types, but it is quite tedious. Is there a way to set the templates properly to do this? SFINAE perhaps?

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
ilya1725
  • 4,496
  • 7
  • 43
  • 68
  • 1
    How is this a template function when there are only 2 types the function can take, and you need a function definition for them? This is just function overloading. – Nicol Bolas Sep 17 '21 at 01:20
  • @NicolBolas I only gave examples of two. There are a lot more. They are just in 2 _categories_. – ilya1725 Sep 17 '21 at 06:11

1 Answers1

1

SFINAE is definitely a solution! I used Templated check for the existence of a class member function? as a reference.

Here's an example of how you might do it. The has_valid type is the important thing; I used it to make a function dispatch, but you could use it other ways too. In your case, you would just call set_valid(vector_array[i]) or whatever from within your read helper.

// SFINAE check for if T has member valid
// note this doesn't check that the member is a bool
template<class T>
class has_valid
{
    template<class X>
    static std::true_type check(decltype(X::valid));

    // Use this version instead if you want to 
    // check if X::valid is explicitly a bool
    /*
    template<class X>
    static std::true_type check(std::enable_if_t<
                                     std::is_same_v<decltype(X::valid), bool>,
                                     bool
                                >);
    */

    template<class X>
    static std::false_type check(...);

  public:
    using type = decltype(check<T>(true));
    constexpr static auto value = type();
};

// Friendly helpers
template<class T>
using has_valid_t = typename has_valid<T>::type;

template<class T>
constexpr static auto has_valid_v = has_valid<T>::value;

// Function dispatcher; call set_valid, which will use has_valid_t to
// dispatch to one of the overloads of dispatch_set_valid, where you can
// either set or not set the value as appropriate
template<class T>
void dispatch_set_valid(T& t, std::false_type)
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

template<class T>
void dispatch_set_valid(T& t, std::true_type)
{
    t.valid = true;
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

template<class T>
void set_valid(T& t)
{
    dispatch_set_valid(t, has_valid_t<T>());
}

See it in action on compiler explorer: https://godbolt.org/z/sqW17WYc6

Ipiano
  • 234
  • 1
  • 8