Search code examples
c++templatesexceptionvariantdecltype

How can I avoid having to use decltype when calling this template?


I have the following code, which I use to automatically catch bad_variant_access errors. I am aware that I can use get_if to simplify error handling, but in this particular case, I do not want a pointer. This code seems to work, but is redundant. As you can see I always have to do assert_no_bad_variant_access<decltype(v), int>(v, "msg");. Could I somehow simplify this to avoid having to pass the decltype(v)? Seems wordy to me.

Ideally, I would like to have a template to which I only have to pass get_T. variant_T should somehow be determined automatically.

Play with the code.

template <typename variant_T, typename get_T>
get_T assert_no_bad_variant_access(variant_T& v, std::string_view msg) {
  try {
    return std::get<get_T>(v);
  } catch (const std::bad_variant_access& bva) {
    std::cout << msg << '\n';
    get_T t;
    return t;
  }
}

int main() 
{

    std::variant<int, double, std::string> v = "hi there!";
    auto result1 = assert_no_bad_variant_access<decltype(v), std::string>(v, "std::string failed");
    auto result2 = assert_no_bad_variant_access<decltype(v), int>(v, "int failed");
    return 0;   
}

Solution

  • Reorder the template parameters. Let variant_T be second, and so it may get deduced

    template <typename get_T, typename variant_T>
    get_T assert_no_bad_variant_access(variant_T& v, std::string_view msg) {
      try {
        return std::get<get_T>(v);
      } catch (const std::bad_variant_access& bva) {
        std::cout << msg << '\n';
        get_T t;
        return t;
      }
    }
    
    int main() 
    {
    
        std::variant<int, double, std::string> v = "hi there!";
        auto result1 = assert_no_bad_variant_access<std::string>(v, "std::string failed");
        auto result2 = assert_no_bad_variant_access<int>(v, "int failed");
        return 0;   
    }
    

    Remember, we can get away with specifying part of the template's arguments only if the trailing ones can be deduced.

    As an aside, you don't need to use exceptions to detect this condition. The std::variant API includes std::holds_alternative. You can check it directly. This will avoid using exceptions for regular flow of control.