Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/153.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 函数模板专门化失败:编码错误或MSVC2013错误?_C++_Templates_Visual C++ - Fatal编程技术网

C++ 函数模板专门化失败:编码错误或MSVC2013错误?

C++ 函数模板专门化失败:编码错误或MSVC2013错误?,c++,templates,visual-c++,C++,Templates,Visual C++,下面的代码使用g++4.8.1(mingw)和上的各种最新clang和gcc版本正确编译,但是使用MSVC2013更新4它失败了,这显然是由于typedef typename a::value_type value_type行。编译器出现以下错误: x、 cpp(30):错误C2893:未能专门化函数模板“void B::bar(void)” 使用以下模板参数: “MemberFn=void C::baz(int)” 更简单的typedeftypedef T value_type工作 我做错什么

下面的代码使用g++4.8.1(mingw)和上的各种最新clang和gcc版本正确编译,但是使用MSVC2013更新4它失败了,这显然是由于
typedef typename a::value_type value_type行。编译器出现以下错误:

x、 cpp(30):错误C2893:未能专门化函数模板“
void B::bar(void)
” 使用以下模板参数: “
MemberFn=void C::baz(int)

更简单的typedef
typedef T value_type工作

我做错什么了吗?或者这是微软C++编译器中的一个已知错误? 补充问题:

  • 从风格的角度来看,假设我有选择权,那么在派生类中重新定义类型(例如
    typedef T value\u type;
    )或者从基类中引入类型(例如
    typedef typename a::value\u type;
    ,或者在C++11
    中使用typename a::value\u type;
    )会更习惯吗?(注意:我现在正在回避C++03兼容性,因此避免使用
    )这里有一些不确定的讨论:我问的原因是如果
    typedef T value\u type是首选,我不需要太担心
#包括
模板
结构A{
类型定义为基本类型;
类型定义T值_类型;
};
模板
结构B:公共A{
typedef派生_类型;
//typedef T value_type;//这是有效的
typedef typename A::value\u type value\u type;//在MSVC 2013中失败
//使用typename A::value_type;//在MSVC 2013中也会失败
模板
空条()
{
(静态演员表(本)->*成员fn)(42);
}
};
结构C:公共B{
虚空巴兹(国际一)
{
标准::printf(“baz(%d)\n”,i);
}
void foo()
{
bar();
}
};
int main(int,char*[])
{
C C;
c、 foo();
}
更新#1:这是一个简化的框架测试用例。我不是要求对结构进行一般性的批评。我不希望结构在没有上下文的情况下有意义

更新#2:这里有一个相关问题,讨论
使用
类型名
结合使用是否有效:


更新#3:我在Microsoft Connect上提交了一份公开的错误报告。如果你能重现这个问题,并且相信它是一个bug,请对bug进行升级:

看起来不错。我用VS2015测试了它,同样的错误信息。事实上,它应该在B中没有typedef的情况下工作,因为它从A继承了“value_type”,因此如果结构B,它也在命名空间中。

我有一个可能的解决方案(我只能用VS2015测试这个)

如果将基类型本身用作模板参数,则会解析它,并且可以访问
值\u type

template <typename T>
struct A {
    typedef T value_type;
    typedef A<T> base_type;
};

template <typename Derived, typename T, typename Base = A<T>>
struct B : public Base
{
    typedef Derived derived_type;
    typedef void (derived_type::*member_func_type)(typename Base::value_type);

    template<member_func_type MemberFn>
    void bar()
    {
        (static_cast<derived_type*>(this)->*MemberFn)(42);
    }
};


struct C : public B<C, int> 
{
    void baz(int i)
    {
        std::printf("baz(%d)\n", i);
    }

    void foo()
    {
        bar<&C::baz>();
    }
};
例如:

template <typename T>
struct D {
    typedef D<T>    base_type;
    typedef T       value_type;
};

struct E : public B<C, int, D<int>>
{
};

更新:

更改
B
模板参数的顺序会更改行为。在这里,只有
T
派生的
顺序的原始代码发生了变化

#include <cstdio>

template <typename T>
struct A {
    typedef A<T> base_type;
    typedef T value_type;
};

template <typename T, typename Derived>
struct B : public A<T> {
    typedef Derived derived_type;
    //typedef T value_type; // this works
    typedef typename A<T>::value_type value_type; // this fails in MSVC 2013
                                                  //using typename A<T>::value_type; // this fails in MSVC 2013 too

    template<void (derived_type::*MemberFn)(value_type) >
    void bar()
    {
        (static_cast<derived_type*>(this)->*MemberFn)(42);
    }
};

struct C : public B<int, C> {
    void baz(int i)
    {
        std::printf("baz(%d)\n", i);
    }

    void foo()
    {
        bar<&C::baz>();
    }
};


int main(int, char *[])
{
    C c;
    c.foo();
}
#包括
模板
结构A{
类型定义为基本类型;
类型定义T值_类型;
};
模板
结构B:公共A{
typedef派生_类型;
//typedef T value_type;//这是有效的
typedef typename A::value\u type value\u type;//在MSVC 2013中失败
//使用typename A::value_type;//在MSVC 2013中也会失败
模板
空条()
{
(静态演员表(本)->*成员fn)(42);
}
};
结构C:公共B{
虚空巴兹(国际一)
{
标准::printf(“baz(%d)\n”,i);
}
void foo()
{
bar();
}
};
int main(int,char*[])
{
C C;
c、 foo();
}
这可以编译并运行良好

我仍然不能完全确定这是否是一个bug


更新

因此,这似乎是MSVC中缺少的功能。MSVC(截至2015/14.0)似乎不支持“两阶段名称查找”

Darran Rowe:VC没有实现C++98/03的三个特性:两阶段 名称查找、动态异常规范和导出。两相 名称查找在2015年仍未实现,但它是在编译器上实现的 团队要做的事情列表,等待代码库现代化。动态 异常规范也未实现(VC给出 非标准语义(抛出()并忽略其他形式),但它们 在C++11中被弃用,现在没有人关心它们了 不例外。我们不太可能实现它们,而且 甚至有人说要从C++17中删除它们。最后,出口受到限制 在C++11中删除

来源

2012年出现了一个请求该功能的bug,但它在没有任何评论的情况下被关闭:


这样看来,您在这里做的一切都是正确的,但是MSVC不支持C++标准的这一部分。

MVSC2014不存在,它的2013或15,但是如果它的更新4可能是13代码,TyPulf Type命名A::ValueEyType ValueSyType;code>或此文件的任何其他版本不应被要求,因为
值\u类型
可以从
A
@Creris继承,谢谢。我已将标题和问题更新为MSVC2013。@SimonKraemer
value\u type
是一个依赖类型。不合格不能使用。你可以(理论上)在任何地方写:
typename A::value\u type
。是的,但是你可以用
typename B::value\u type
做同样的事情。那么,您的观点是什么?感谢您在VS2015中进行测试。但是,我不认为类型可以在没有限定的情况下从依赖类型继承。请注意,基类
A
依赖于
B
的类型参数(即
B
也是一个模板)。我不能给您一个ISO-link atm,但当一个类从另一个类继承时,您可以访问基类中所有定义的名称(关于public、proteced和private)。不管它是模板还是
template <typename T>
struct D {
    typedef D<T>    base_type;
    typedef T       value_type;
};

struct E : public B<C, int, D<int>>
{
};
error C2338: Redefinition of template parameter Base is not allowed
#include <cstdio>

template <typename T>
struct A {
    typedef A<T> base_type;
    typedef T value_type;
};

template <typename T, typename Derived>
struct B : public A<T> {
    typedef Derived derived_type;
    //typedef T value_type; // this works
    typedef typename A<T>::value_type value_type; // this fails in MSVC 2013
                                                  //using typename A<T>::value_type; // this fails in MSVC 2013 too

    template<void (derived_type::*MemberFn)(value_type) >
    void bar()
    {
        (static_cast<derived_type*>(this)->*MemberFn)(42);
    }
};

struct C : public B<int, C> {
    void baz(int i)
    {
        std::printf("baz(%d)\n", i);
    }

    void foo()
    {
        bar<&C::baz>();
    }
};


int main(int, char *[])
{
    C c;
    c.foo();
}