Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.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++ 没有名为'的类型;类型';在CTRP派生类中_C++_Templates_Non Virtual Interface - Fatal编程技术网

C++ 没有名为'的类型;类型';在CTRP派生类中

C++ 没有名为'的类型;类型';在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(工作)

我一直在试验一个通用的单参数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(工作)
模板
类函数接口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;
};