Home > Software design >  how do I make a conditional statement to ignore std::string types when using template parameters?
how do I make a conditional statement to ignore std::string types when using template parameters?

Time:12-05

I'm encountering issues when I try to use this operator () function in a class on a string object instead of a char or numeric data type. I tried the following implementation to check if the data being iterated over is a std::string, but the function is still returning an error when this part of the code is executed:

this->current -= this->range->step;

This makes sense, sense you can't perform that operation on a std::string, however my current method of making an exception for strings isn't quite working right, it keeps throwing:

error: no match for 'operator-=' (operand types are 'std::__cxx11::basic_string<char>' and 'std::__cxx11::basic_string<char>' this->current -= this->range->step;

Any ideas on a better implementation, or perhaps a different way to write this code?

Iterator& operator  () {
    bool isStr = false;
    std::string str = "s"; 
    auto cmp = this->range->step;
    if (typeid(cmp) == typeid(str)) { // check if the variable is a string
      isStr = true;
    }
    if (this->range->stop > this->range->start || isStr) { // if increasing, or working w/ strings
        this->current  =  range->step;
        return *this;
      } else if (this->range->stop < this->range->start) { // if decreasing
        if (!isStr) {
        this->current -= this->range->step;
        }
      }
    return *this;
}

CodePudding user response:

You are checking the type at runtime, which won't work. You need to check the type at compile time instead.

In C 17 and later, you can use if constexpr for that, eg:

#include <type_traits>

Iterator& operator  () {
    if constexpr (std::is_same_v<decltype(range->step), std::string>) { // check if the variable is a string
        current  = range->step;
    }
    else if (range->stop > range->start) { // if increasing
        current  = range->step;
    }
    else if (range->stop < range->start) { // if decreasing
        current -= range->step;
    }
    return *this;
}

In earlier C versions, you will have to instead overload the operator using SFINAE (std::enable_if(), etc) or template specialization to isolate the std::string version of the operator into its own separate implementation.

CodePudding user response:

Like your code this isn't complete and won't compile. But when working with code that should make choices dependent on type use compile time constructs! Use things, like "overloading", "templates", "if constexpr", "SFINAE". For example :

#include <type_traits>
#include <string>

struct foo_t
{
    template<typename type_t>
    auto& operator  ()
    {
        if constexpr (std::is_same_v<type_t, std::string>) // <== check types at compile time!
        {
            // working with strings we go only one way
            current  = range->step;
            return *this;
        }
        else
        {
            // if increasing
            if (range->stop > range->start )
            { 
                current  = range->step;
                return *this;
            }
            else if (range->stop < range->start) 
            { 
                current -= range->step;
            }
        }
        return *this;
    }
};
  •  Tags:  
  • c
  • Related