I have boiled my error down to this case. I have a snippet of a custom variant based on the variant code in maplibre-gl. This inherits from std::variant
with some extra template checks on its own constructor. I define my own BaseVariant
as an instance of this variant, and then define two classes: ValueFromBaseVariant
which inherits directly from BaseVariant
, and ValueFromDerivedVariant
which inherits from BaseVariant
via DerivedVariant
(which is empty but inherits the BaseVariant
constructors):
#include <functional>
#include <tuple>
#include <type_traits>
#include <variant>
namespace maplibre {
template <typename T, typename... Types>
struct DirectType {
static constexpr bool is_direct = (std::is_same_v<T, Types> || ...);
};
template <typename T, typename... Types>
struct ConvertibleType {
static constexpr bool is_convertible = (std::is_convertible<T, Types>::value || ...);
};
template <typename T, typename... Types>
struct ValueTraits {
using ValueType = typename std::remove_const<typename std::remove_reference<T>::type>::type;
static constexpr bool is_valid = DirectType<ValueType, Types...>::is_direct || ConvertibleType<ValueType, Types...>::is_convertible;
};
template <typename... Types>
class variant : public std::variant<Types...> {
private:
using base_variant = std::variant<Types...>;
using current_variant = variant<Types...>;
public:
variant() : base_variant() {}
template <typename T,
typename CurrentTraits = ValueTraits<T, Types...>,
typename Enabled = typename std::enable_if<CurrentTraits::is_valid && !std::is_same_v<current_variant, typename CurrentTraits::ValueType>>::type>
variant(T&& val) : base_variant(std::forward<T>(val)) {}
};
} // namespace maplibre
using BaseVariant = maplibre::variant<bool, int>;
class DerivedVariant : private BaseVariant {
public:
using BaseVariant::BaseVariant;
};
// Works for all compilers
class ValueFromBaseVariant : public BaseVariant
{
public:
ValueFromBaseVariant(bool b) : BaseVariant(b) {}
};
// Works for gcc/clang, error for MSVC
class ValueFromDerivedVariant : public DerivedVariant
{
public:
ValueFromDerivedVariant(bool b) : DerivedVariant(b) {}
};
On all compilers I've tried (clang, gcc, msvc), ValueFromBaseVariant
compiles ok. But ValueFromDerivedVariant
only compiles on clang and gcc. With msvc it gives the following error:
example.cpp
<source>(60): error C2665: 'DerivedVariant::DerivedVariant': no overloaded function could convert all the argument types
<source>(46): note: could be 'DerivedVariant::DerivedVariant(DerivedVariant &&)'
<source>(60): note: 'DerivedVariant::DerivedVariant(DerivedVariant &&)': cannot convert argument 1 from 'bool' to 'DerivedVariant &&'
<source>(60): note: Reason: cannot convert from 'bool' to 'DerivedVariant'
<source>(46): note: or 'DerivedVariant::DerivedVariant(const DerivedVariant &)'
<source>(60): note: 'DerivedVariant::DerivedVariant(const DerivedVariant &)': cannot convert argument 1 from 'bool' to 'const DerivedVariant &'
<source>(60): note: Reason: cannot convert from 'bool' to 'const DerivedVariant'
<source>(46): note: or 'DerivedVariant::DerivedVariant(void)'
<source>(60): note: 'DerivedVariant::DerivedVariant': function does not take 1 arguments
<source>(45): note: or 'DerivedVariant::DerivedVariant(T &&)', which inherits 'maplibre::variant<bool,int>::variant(T &&)' via base class 'maplibre::variant<bool,int>'
<source>(60): note: 'DerivedVariant::DerivedVariant(T &&)': could not deduce template argument for 'CurrentTraits'
<source>(60): note: 'Types': parameter pack cannot be used in this context
<source>(60): note: while trying to match the argument list '(bool)'
Compiler returned: 2
Godbolt links: msvc: https://godbolt.org/z/sv99qnn9P gcc: https://godbolt.org/z/5soz1oMeh
Have I done something wrong and gcc/clang are being lenient, or is msvc missing something? Thanks
The program is well-formed. This seems to be a msvc bug.
MSVC rejects valid program involving using using declaration to inherit constructor