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