从可变参数模板继承时访问基本 class 函数时出现不明确的访问错误

Ambiguous access error when accessing base class functions while inheriting from variadic template

我正在尝试创建 class 派生自可变参数模板。这是代码:

struct Some { };

template < class Base, class T >
struct Feature
{
protected:
    void DoStuff(T& t) { }
};

template < class T, class ... Ts >
struct MultiFeature
    : public Feature< T, Ts >...
{

};

class TestFeature
    : public MultiFeature< Some, std::int16_t, std::string >
{
public:
    void TestDoStuff()
    {
        std::int16_t i;
        DoStuff(i);
    }
};

Feature 应该是一些基本类型(在本例中为整数和字符串)的简单包装,为从中派生的 class 提供一些功能。使用 MultiFeature 这样我就不必从 Feature< std::int16_t >Feature< std::string > 派生。

据我了解,在这种情况下应该没有歧义,因为有两个不同的 DoStuff 函数,每个函数采用不同的参数类型,但是 VS2017 抱怨访问不明确。这是正确的行为吗?如果是这样,是否有解决此问题的简单解决方法?

编辑

似乎编译器就在这里,但是在这个答案中,建议的解决方法是将基础 class 成员函数带入 using (Ambiguous access to base class template member function) 的范围。是否有可能以某种方式对可变模板基础 class 执行此操作?

It seems that compiler is right here, however in this answer, suggested workaround for this is to bring base class member functions into scope with using (Ambiguous access to base class template member function). Is it somehow possible to do this for variadic template base class?

如果你会用C++17,那就简单了

template <typename T, typename ... Ts>
struct MultiFeature : public Feature<T, Ts>...
 {
   using Feature<T, Ts>::DoStuff...;
 };

不幸的是,可变参数 using 在 C++17 中引入,所以在 C++11 和 C++14 中,我能想象的最好的是 MultiFeature 递归定义

// ground case: a fake DoStuff to abilitate following using
template <typename T, typename ... Ts>
struct MultiFeature
 { void DoStuff () { } };

// recursion case
template <typename T, typename T0, typename ... Ts>
struct MultiFeature<T, T0, Ts...>
   : public Feature<T, T0>, public MultiFeature<T, Ts...>
 {
   using Feature<T, T0>::DoStuff;
   using MultiFeature<T, Ts...>::DoStuff;
 };

下面是一个完整的编译示例(两种情况)

struct Some { };

template <typename, typename T>
struct Feature
 {
   protected:
      void DoStuff (T &) { }
 };

#if 0
template <typename T, typename ... Ts>
struct MultiFeature : public Feature<T, Ts>...
 {
   using Feature<T, Ts>::DoStuff...;
 };
#else
// ground case: a fake DoStuff to abilitate following using
template <typename T, typename ... Ts>
struct MultiFeature
 { void DoStuff () { } };

// recursion case
template <typename T, typename T0, typename ... Ts>
struct MultiFeature<T, T0, Ts...>
   : public Feature<T, T0>, public MultiFeature<T, Ts...>
 {
   using Feature<T, T0>::DoStuff;
   using MultiFeature<T, Ts...>::DoStuff;
 };
#endif

struct TestFeature
   : public MultiFeature<Some, short, int, long, long long>
 {
   void TestDoStuff ()
    { int a{}; DoStuff(a); }
 };


int main ()
 {
   TestFeature tf;
 }