vs2015在可变参数模板中找不到重载的成员函数

摩根

我试图将其归结为要点。我有一个可变的模板类Foo,其中包含用其类型索引的对象的“列表”。我使用函数bar<U>()来提取该类型的元素。我使用可变参数模板和std :: enable_if来解决此问题,仅定义bar<U>()T ==U。然后使用“ using”公开基类中的所有“ bar”函数。

#include <type_traits>

template<typename... Ts>
class Foo
{
public:
    void bar() {}
};

template<typename T, typename... Ts>
class Foo<T, Ts...> : public Foo<Ts...>
{
public:
    using Foo<Ts...>::bar;

    template<typename U>
    typename std::enable_if<std::is_same<U, T>::value, U >::type
        bar()
    {
        return mObj;
    }
private:
    T mObj;
};

template<typename T>
void bar2()
{
    Foo<int, float, double> list;
    list.bar<T>();
}

int main()
{
    bar2<float>();
    return 0;
}

除了在Clang和Visual Studio 2015上之外,这都工作得很好。尝试了MSVC 19.0和19.10并给出错误:

Compiled with  /EHsc /nologo /W4 /c
main.cpp
main.cpp(30): error C2672: 'Foo<int,float,double>::bar': no matching overloaded function found
main.cpp(35): note: see reference to function template instantiation 'void bar2<float>(void)' being compiled
main.cpp(30): error C2770: invalid explicit template argument(s) for 'std::enable_if<std::is_same<U,T>::value,U>::type Foo<int,float,double>::bar(void)'
        with
        [
            T=int
        ]
main.cpp(18): note: see declaration of 'Foo<int,float,double>::bar'

至少在4.7-6.3之间的GCC可以编译此罚款。我首先认为这可能是Visual Studio 2015中缺少c ++ 11的某些功能,但是令人惊讶的是,这在较旧的Visual Studio 2013(MSVC 18.0)中可以很好地编译。lang也失败。

所以我的问题是,这是这些编译器的缺点,还是我在这里不允许做的事情?

如果我用硬编码类型调用“ bar”,list.bar<int>()它将在所有经过测试的编译器上编译。

贾斯汀时间-恢复莫妮卡

enable_if在此处使用,您需要为when提供一个替代选项is_same<U, T>::value == false理想情况下,这可以通过向所有基类成员bar使用using声明来实现

using Foo<Ts...>::template bar;

不幸的是,这是标准所禁止的,因此决定不对此进行纠正因此,我们必须以其他方式公开它们。因此,最简单的解决方案是为制作包装Foo<Ts...>::template bar(),如下所示:

template<typename T, typename... Ts>
class Foo<T, Ts...> : public Foo<Ts...>
{
public:
    // using Foo<Ts...>::template bar; // Sadly, this is forbidden.

    template<typename U>
    typename std::enable_if<std::is_same<U, T>::value, U >::type
        bar()
    {
        return mObj;
    }

    // Additional wrapper, to compensate for lack of valid syntax.
    template<typename U>
    typename std::enable_if<!std::is_same<U, T>::value, U >::type
        bar()
    {
        return Foo<Ts...>::template bar<U>();
    }

private:
    T mObj;
};

但是请注意,Foo<Ts...>::bar()由于返回,包装器无法调用void假定这是通用情况,打算在U不属于包的情况下使用,有两种方法可以纠正此问题:

  • 修改Foo<Ts...>::bar()

    template<typename... Ts>
    class Foo
    {
    public:
        template<typename T>
        T bar()
        {
            // Return an invalid value.
            return T{-1};
        }
    };
    
  • 提供的第三版Foo<T, Ts...>::bar(),当U不是成员时使用T, Ts...; 这一回Foo<Ts...>::bar()为此,定义一个特征以检测其是否在包装中将很有用。

    template<typename...>
    struct is_in_pack : std::false_type {};
    
    template<typename U, typename T1, typename... Ts>
    struct is_in_pack<U, T1, Ts...> :
        std::integral_constant<bool,
                               std::is_same<U, T1>::value ||
                               is_in_pack<U, Ts...>::value>
    {};
    

    然后,我们只需要使用该特征。

    template<typename T, typename... Ts>
    class Foo<T, Ts...> : public Foo<Ts...>
    {
    public:
        // using Foo<Ts...>::template bar; // Sadly, this is forbidden.
    
        template<typename U>
        typename std::enable_if<std::is_same<U, T>::value, U >::type
            bar()
        {
            return mObj;
        }
    
        // Additional wrapper, to compensate for lack of valid syntax.
        // U is a member of <T, Ts...>.
        template<typename U>
        typename std::enable_if<!std::is_same<U, T>::value &&
                                is_in_pack<U, T, Ts...>::value, U >::type
            bar()
        {
            return Foo<Ts...>::template bar<U>();
        }
    
        // Additional wrapper, to compensate for lack of valid syntax.
        // U isn't a member of <T, Ts...>.
        template<typename U>
        typename std::enable_if<!is_in_pack<U, T, Ts...>::value>::type
            bar()
        {
            return Foo<>::bar();
        }
    
    private:
        T mObj;
    };
    

在这些选项中,我建议使用后者,因为它与您当前的代码更加匹配。

测试简单
复杂的测试

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

以成员函数指针为参数的可变参数模板

可变参数模板成员函数的部分专业化

如何将可变参数模板成员函数的参数存储到向量中?

在可变参数模板类的构造函数中初始化元组成员

具有可变参数模板的成员函数指针

可变参数模板继承中的运算符重载

如何在SWIG中包装可变参数模板类的可变参数模板成员函数?

C ++:可变参数模板和函数重载

专业化可变参数模板成员函数

从可变参数模板类中提取类型以实现成员函数重载

可变参数函数和可变参数模板重载查找

可变参数模板函数中对重载函数的歧义调用

重载可变参数模板化方法

可变参数模板中的成员要求不明确

在VS2013中使用可变参数模板时“对重载函数的歧义调用”

如何重载可变参数模板函数?

VS2015:可变参数模板专业化

std :: function到可变参数成员函数,然后绑定可变参数模板参数

可变参数模板类-可变参数成员函数

可变参数模板函数重载失败

使用成员函数调用可变参数模板函数

完美转发可变参数模板参数到成员函数

由于#define,VS2015 找不到成员函数 [c++] 定义

带有可变参数模板参数的重载函数

可变参数模板中的函数顺序

继承可变参数模板中基本成员的名称隐藏

std::invoke 不喜欢可变参数模板成员函数?

什么是可变参数函数模板重载优先规则?

为什么可变参数模板找不到合适的构造函数?