Search code examples
c++templatesc++17type-deduction

Deduce first type from second non-type parameter of first type


I have following function:

/// <summary>
/// Check whether next character in std::basic_istream is what expected. Skip it if so; otherwise, set fail flag.
/// </summary>
template <typename TCharType, TCharType char_>
std::basic_istream<TCharType>& skipIf(std::basic_istream<TCharType>& istream_)
{
    if ((istream_ >> std::ws).peek() == char_) {
        istream_.ignore();
    }
    else {
        istream_.setstate(std::ios_base::failbit);
    }
    return istream_;
}

It works like this:

std::istringstream is {"some ; string"};
std::string temp;
if(is >> temp >> skipIf<char, ';'> >> temp) {
    // blah blah
}

Is there way to deduce TCharType from given char_ template parameter? It would be nice if I could write just

  • skipIf<';'> -> deduced to char
  • skipIf<L';'> -> deduced to wchar_t
  • skipIf<u';'> -> deduced to char16_t
  • skipIf<U';'> -> deduced to char32_t

Solution

  • You can do that with C++17's new auto non-type template parameters. A bit of rearranging:

    template <auto char_, typename TCharType = decltype(char_)>
    std::basic_istream<TCharType>& skipIf(std::basic_istream<TCharType>& istream_)
    {
        if ((istream_ >> std::ws).peek() == char_) {
            istream_.ignore();
        }
        else {
            istream_.setstate(std::ios_base::failbit);
        }
        return istream_;
    }
    

    And you should get what you are after, exactly. You can probably improve it by adding a few more checks (either as a static_assert or SFINAE) to make sure TCharType is indeed one of the standard or extended character types, but that's the cookbook solution.