Container that holds objects of various types, and can be searched for an object convertible to a given type I built a container that can hold objects of various types, and look up an object convertible to a given type.  I wrote something about my intended use-case here:

https://stackoverflow.com/questions/58562173/typesafe-way-to-provide-enriched-dependencies-to-derived-classes-in-c

Basically I want to be able to throw a bunch of dependencies onto a pile and then grab the exact version I want from calling code -- for instance, if I just need an IWidget, I can do

IWidget * widget = dependencies.get&lt;IWidget *&gt;();


but if the underlying widget is actually a FancyGreenWidget then I can do

FancyGreenWidget * widget = dependencies.get&lt;FancyGreenWidget *&gt;();


and if it's not fancy and green then I'll get a helpful runtime error during program initialization rather than a surprise segfault sometime while the program is running.

I'm not really familiar with C++17, but it seemed like I needed a bunch of C++17 features to implement my use-case.  I feel like someone who writes modern C++ on a daily basis can probably glance at this and tell me several things I'm doing wrong.  In particular I suspect there's a much cleaner way to write the visitor in the get&lt;T&gt;() method.

template&lt;class... Types&gt;
  class VariantContainer
  {
    private:

      std::vector&lt;std::variant&lt;Types...&gt;&gt; m_values;

    public:

      template&lt;class T&gt;
      void add(const T &amp;t)
      {
        static_assert(std::disjunction_v&lt;std::is_same&lt;T, Types&gt;...&gt;);

        m_values.push_back(t);
      }

      template&lt;class T&gt;
      T get()
      {
        for(int i = 0; i &lt; m_values.size(); i++)
        {
          std::optional&lt;T&gt; result = std::visit(
            [](auto&amp;&amp; arg) {
              using Targ = std::decay_t&lt;decltype(arg)&gt;;

              if constexpr(std::is_convertible_v&lt;Targ, T&gt;)
              {
                return std::optional&lt;T&gt;(static_cast&lt;T&gt;(arg));
              }
              else
              {
                return std::optional&lt;T&gt;();
              }
          },
          m_values[i]);

          if(result.has_value()) { return result.value(); }
        }

        std::string message = "Could not find member of type ";
        message += abi::__cxa_demangle(typeid(T).name(), 0, 0, nullptr);

        throw std::runtime_error(message);
      }
  };


Sample usage:

    VariantContainer&lt;Base *, Derived1 *, Derived2 *&gt; v;

    Derived2 d;

    v.add(&amp;d);

    Base * b = v.get&lt;Base *&gt;(); // returns a pointer to d

    Derived1 * d1 = v.get&lt;Derived1 *&gt;(); // ERROR

    Derived2 * d2 = v.get&lt;Derived2 *&gt;(); // returns a pointer to d


I'm also in the market for a more descriptive name for this class if anyone has any ideas.
You said you implemented


  a container that can hold objects of various types, and look
  up an object convertible to a given type


This idea can be simplified and generalized: we want to


  look up an object convertible to a given a type in a sequence of variants


We can focus on the get function and strip everything else.  The container does not have to be a std::vector&lt;std::variant&gt; &mdash; we can use iterators:

template &lt;typename T, typename ForIt&gt;
T get_convertible(ForIt first, ForIt last);


In the code, you want to find an element that is convertible to T, and throw an exception if such an element is not found.  You used std::optional to conditionally return the visited element.  This overhead can be eliminated:

template &lt;typename T, typename ForIt&gt;
T get_convertible(ForIt first, ForIt last)
{
    auto it = std::find_if(first, last, [](const auto&amp; variant) {
        return std::visit([](const auto&amp; value) {
            using U = std::decay_t&lt;decltype(value)&gt;;
            return std::is_convertible_v&lt;U, T&gt;;
        }, variant);
    });

    if (it == last) {
        throw std::runtime_error{"..."};
    } else {
        return std::visit([](const auto&amp; value) -&gt; T {
            using U = std::decay_t&lt;decltype(value)&gt;;
            if constexpr (std::is_convertible_v&lt;U, T&gt;)
                return value;
        }, *it);
    }
}


(live demo, includes code to disable return warning)