C++ 没有名为'的类型;类型';在CTRP派生类中
我一直在试验一个通用的单参数functor,并有两个实现:一个使用一个有效的模板参数,另一个尝试访问接口类中的派生functor::type。在后一个示例中,编译器(gcc 5.4.0)报告 错误:在“struct CubeC++ 没有名为'的类型;类型';在CTRP派生类中,c++,templates,non-virtual-interface,C++,Templates,Non Virtual Interface,我一直在试验一个通用的单参数functor,并有两个实现:一个使用一个有效的模板参数,另一个尝试访问接口类中的派生functor::type。在后一个示例中,编译器(gcc 5.4.0)报告 错误:在“struct Cube”中没有名为“类型”的类型 模板 类函数接口_1{ 私人: 常量函子&f_-cref; 公众: 函数接口_1():f_cref(static_cast(*this)){ T运算符()(T val)常量{return f_cref(val);} }; // 功能接口_1(工作)
模板
类函数接口_1{
私人:
常量函子&f_-cref;
公众:
函数接口_1():f_cref(static_cast(*this)){
T运算符()(T val)常量{return f_cref(val);}
}; // 功能接口_1(工作)
模板
类函数接口2{
私人:
常量函子&f_-cref;
公众:
使用Ftype=typename Functor::type;
函数接口_2():f_cref(static_cast(*this)){
Ftype运算符()(Ftype val)常量{return f_cref(val);}
}; // FunctorInterface_2(在Functor中没有类型!)
然后,我尝试在main()中使用T=double编译以下两个类:
template<class T>
struct Square : public FunctorInterface_1<T,Square> {
T operator()( T val ) const { return val*val; }
}; // Square
template<class T>
struct Cube : public FunctorInterface_2<Cube<T>> {
using type = T;
T operator() ( T val ) const { return val*val*val; }
}; // Cube
模板
struct Square:公共函数接口_1{
T运算符()(T val)常量{return val*val;}
}; // 广场
模板
结构多维数据集:公共函数接口_2{
使用类型=T;
T运算符()(T val)常量{return val*val*val;}
}; // 立方体
FunctionInterface_2/Cube示例是否可以修改为工作,或者
是否有必要将接口类模板化在T as上
在第一个例子中?谢谢
编辑:使用gcc-std=c++14,我可以编译并运行第二个示例
但是,据我所知,通过在FunctorInterface_1::operator()中使用自动返回和参数类型,自动参数类型不是C++14标准的一部分
编辑2:我觉得有点胖。我刚刚意识到我可以在一个新参数上模板FunctionInterface_1::operator(),但是,对于我想到的应用程序,我真的希望我的基类能够访问派生类中定义的类型 您的代码可以简化为
template<typename TDerived> class
Base
{
using Ftype = typename TDerived::type;
};
template<typename T> class
Derived: public Base<Derived<T>>
{
using type = T;
};
Derived<int> wat;
模板类
基础
{
使用Ftype=typename TDerived::type;
};
模板类
来源:公共基地
{
使用类型=T;
};
导出wat;
它不起作用,因为在Base
实例化Derived
类的点未完成,并且编译器还不知道Derived::type
是否存在
using Ftype = typename Functor::type;
是在基类中处理的,函子
的定义不可用。因此,不能使用Functor::type
绕过此限制的一种方法是定义traits类
// Declare a traits class.
template <typename T> struct FunctorTraits;
template<class Functor>
class FunctorInterface_2 {
private:
const Functor &f_cref;
public:
// Use the traits class to define Ftype
using Ftype = typename FunctorTraits<Functor>::type;
FunctorInterface_2() : f_cref(static_cast<const Functor&>(*this)) {}
Ftype operator() ( Ftype val ) const { return f_cref(val); }
}; // FunctorInterface_2 (no type in Functor!)
// Forward declare Cube to specialize FunctorTraits
template<class T> struct Cube;
// Specialize FunctorTraits for Cube
template <typename T> struct FunctorTraits<Cube<T>>
{
using type = T;
};
template<class T>
struct Cube : public FunctorInterface_2<Cube<T>> {
using type = T;
T operator() ( T val ) const { return val*val*val; }
}; // Cube
//声明一个traits类。
模板结构函数;
模板
类函数接口2{
私人:
常量函子&f_-cref;
公众:
//使用traits类定义Ftype
使用Ftype=typename FunctorTraits::type;
函数接口_2():f_cref(static_cast(*this)){
Ftype运算符()(Ftype val)常量{return f_cref(val);}
}; // FunctorInterface_2(在Functor中没有类型!)
//正向声明多维数据集以专门化FunctionTraits
模板结构立方体;
//专门化多维数据集的函数集
模板结构函数
{
使用类型=T;
};
模板
结构多维数据集:公共函数接口_2{
使用类型=T;
T运算符()(T val)常量{return val*val*val;}
}; // 立方体
工作代码:您必须了解,在实例化多维数据集时,首先实例化的是
FunctionInterface\u 2
。这意味着发生这种情况时,Cube
是不完整的类型。因此,当编译器使用
Ftype=typename Functor::type代码>函子
不完整,您无法访问其任何嵌套类型
在您的情况下,您可以将FunctionInterface_2
更改为:
template<class Functor>
class FunctorInterface_2 {
private:
const Functor &f_cref;
public:
FunctorInterface_2() : f_cref(static_cast<const Functor&>(*this)) {}
template <class TT>
auto operator() ( TT && val ) -> decltype(f_cref(val)) const { return f_cref(val); }
};
模板
类函数接口2{
私人:
常量函子&f_-cref;
公众:
函数接口_2():f_cref(static_cast(*this)){
模板
自动运算符()(TT&&val)->decltype(f_cref(val))const{return f_cref(val);}
};
因此,现在访问有关Functor
的信息会被延迟,直到您从FunctionInterface\u 2
调用操作符()
,此时FunctionInterface\u 2
和Cube
完全实例化。注意:这个问题已经由,但我想详细阐述一下这一点,并具体介绍一下clang的输出
这个问题可以在一个小得多的代码示例上演示:(@vtt类似的东西)
模板
结构A{
使用_C=typename _CRTP::C;
};
结构B:公共A{
使用C=int;
};
使用clang编译将导致完全误导的错误消息:()
:3:32:错误:“B”中没有名为“C”的类型
使用_C=typename _CRTP::C;
~~~~~~~~~~~~~~~~^
:6:19:注意:此处请求实例化模板类“A”
结构B:公共A{
^
生成1个错误。
GCC的错误消息更有帮助:()
:在“结构A”的实例化中:
:6:19:从这里开始需要
:3:33:错误:不完整类型“结构B”的使用无效
3 |使用_C=typename _CRTP::C;
| ^
:6:8:注意:“结构B”的转发声明
6 |结构B:公共A{
| ^
正如公认答案中所建议的,实施特质类型可以解决问题:
// this declaration must appear before the definition of A
template <typename _A>
struct a_traits;
template <typename _CRTP>
struct A {
// `a_traits<_CRTP>::type` is an incomplete type at this point,
// but that doesn't matter since `A` is also incomplete
using _C = typename a_traits<_CRTP>::type;
};
// this specialization must appear before the definition of B
template <>
struct a_traits<struct B> { // adding the type specifier `struct` will declare B
using type = int;
};
// specifying the template parameter will complete the type `A<B>`, which works since
// `a_traits<B>` is already complete at this point
struct B : public A<B> {
using C = int;
};
//此声明必须出现在
模板
结构特征;
模板
结构A{
//此时,`a_traits::type`是一个不完整的类型,
//但这并不重要,因为'A'也是不完整的
使用_C=typename a_traits::type;
};
//这种专门化必须出现在B的定义之前
模板
结构a_traits{//添加类型说明符'struct'将声明B
使用type=int;
};
//指定模板参数将完成类型“A”,该类型为
template <typename _CRTP>
struct A {
using _C = typename _CRTP::C;
};
struct B : public A<B> {
using C = int;
};
// this declaration must appear before the definition of A
template <typename _A>
struct a_traits;
template <typename _CRTP>
struct A {
// `a_traits<_CRTP>::type` is an incomplete type at this point,
// but that doesn't matter since `A` is also incomplete
using _C = typename a_traits<_CRTP>::type;
};
// this specialization must appear before the definition of B
template <>
struct a_traits<struct B> { // adding the type specifier `struct` will declare B
using type = int;
};
// specifying the template parameter will complete the type `A<B>`, which works since
// `a_traits<B>` is already complete at this point
struct B : public A<B> {
using C = int;
};