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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/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++;静态多态性(CRTP)和使用派生类的typedef 我读了C++中奇怪的重复模板模式来做静态(读:编译时)多态性。我想对其进行泛化,以便根据派生类型更改函数的返回类型。(这似乎是可能的,因为基类型从模板参数知道派生类型)。不幸的是,下面的代码无法使用MSVC2010编译(我现在无法轻松访问gcc,所以还没有尝试过)。有人知道为什么吗 template <typename derived_t> class base { public: typedef typename derived_t::value_type value_type; value_type foo() { return static_cast<derived_t*>(this)->foo(); } }; template <typename T> class derived : public base<derived<T> > { public: typedef T value_type; value_type foo() { return T(); //return some T object (assumes T is default constructable) } }; int main() { derived<int> a; } 模板 阶级基础{ 公众: typedef typename派生的\u t::value\u type value\u type; 值\类型foo(){ 返回static_cast(this)->foo(); } }; 模板 派生类:公共基{ 公众: 类型定义T值_类型; 值\类型foo(){ return T();//返回一些T对象(假设T是默认可构造的) } }; int main(){ 导出了一个; }_C++_Templates_Inheritance_Typedef_Crtp - Fatal编程技术网

C++;静态多态性(CRTP)和使用派生类的typedef 我读了C++中奇怪的重复模板模式来做静态(读:编译时)多态性。我想对其进行泛化,以便根据派生类型更改函数的返回类型。(这似乎是可能的,因为基类型从模板参数知道派生类型)。不幸的是,下面的代码无法使用MSVC2010编译(我现在无法轻松访问gcc,所以还没有尝试过)。有人知道为什么吗 template <typename derived_t> class base { public: typedef typename derived_t::value_type value_type; value_type foo() { return static_cast<derived_t*>(this)->foo(); } }; template <typename T> class derived : public base<derived<T> > { public: typedef T value_type; value_type foo() { return T(); //return some T object (assumes T is default constructable) } }; int main() { derived<int> a; } 模板 阶级基础{ 公众: typedef typename派生的\u t::value\u type value\u type; 值\类型foo(){ 返回static_cast(this)->foo(); } }; 模板 派生类:公共基{ 公众: 类型定义T值_类型; 值\类型foo(){ return T();//返回一些T对象(假设T是默认可构造的) } }; int main(){ 导出了一个; }

C++;静态多态性(CRTP)和使用派生类的typedef 我读了C++中奇怪的重复模板模式来做静态(读:编译时)多态性。我想对其进行泛化,以便根据派生类型更改函数的返回类型。(这似乎是可能的,因为基类型从模板参数知道派生类型)。不幸的是,下面的代码无法使用MSVC2010编译(我现在无法轻松访问gcc,所以还没有尝试过)。有人知道为什么吗 template <typename derived_t> class base { public: typedef typename derived_t::value_type value_type; value_type foo() { return static_cast<derived_t*>(this)->foo(); } }; template <typename T> class derived : public base<derived<T> > { public: typedef T value_type; value_type foo() { return T(); //return some T object (assumes T is default constructable) } }; int main() { derived<int> a; } 模板 阶级基础{ 公众: typedef typename派生的\u t::value\u type value\u type; 值\类型foo(){ 返回static_cast(this)->foo(); } }; 模板 派生类:公共基{ 公众: 类型定义T值_类型; 值\类型foo(){ return T();//返回一些T对象(假设T是默认可构造的) } }; int main(){ 导出了一个; },c++,templates,inheritance,typedef,crtp,C++,Templates,Inheritance,Typedef,Crtp,顺便说一句,我在使用额外的模板参数方面做了一些工作,但我不喜欢它——在继承链上传递许多类型时,它会变得非常冗长 template <typename derived_t, typename value_type> class base { ... }; template <typename T> class derived : public base<derived<T>,T> { ... }; 模板 类基{…}; 模板 派生类:公共基{…};

顺便说一句,我在使用额外的模板参数方面做了一些工作,但我不喜欢它——在继承链上传递许多类型时,它会变得非常冗长

template <typename derived_t, typename value_type>
class base { ... };

template <typename T>
class derived : public base<derived<T>,T> { ... };
模板
类基{…};
模板
派生类:公共基{…};
编辑:

MSVC 2010在这种情况下给出的错误消息是
error C2039:“value\u type”:不是“派生”的成员。


g++4.1.2(via)表示
错误:“类派生”中没有名为“value\u type”的类型
派生的
在其基类列表中将其作为模板参数使用时是不完整的

一个常见的解决方法是使用traits类模板。这是你的例子,traitsified。这显示了如何通过traits使用派生类中的类型和函数

// Declare a base_traits traits class template:
template <typename derived_t> 
struct base_traits;

// Define the base class that uses the traits:
template <typename derived_t> 
struct base { 
    typedef typename base_traits<derived_t>::value_type value_type;
    value_type base_foo() {
        return base_traits<derived_t>::call_foo(static_cast<derived_t*>(this));
    }
};

// Define the derived class; it can use the traits too:
template <typename T>
struct derived : base<derived<T> > { 
    typedef typename base_traits<derived>::value_type value_type;

    value_type derived_foo() { 
        return value_type(); 
    }
};

// Declare and define a base_traits specialization for derived:
template <typename T> 
struct base_traits<derived<T> > {
    typedef T value_type;

    static value_type call_foo(derived<T>* x) { 
        return x->derived_foo(); 
    }
};
//声明基本类模板:
模板
结构碱基特性;
//定义使用特征的基类:
模板
结构基{
typedef typename base_traits::value_type value_type;
值\u类型基本\u foo(){
return base_traits::call_foo(static_cast(this));
}
};
//定义派生类;它也可以使用以下特征:
模板
派生结构:基{
typedef typename base_traits::value_type value_type;
值\u类型派生的\u foo(){
返回值_type();
}
};
//声明并定义派生属性的基本属性专用化:
模板
结构基特征{
类型定义T值_类型;
静态值\u类型调用\u foo(派生*x){
返回x->派生的_foo();
}
};

您只需对用于
base
的模板参数
derived\u t
的任何类型的
base\u traits
进行专门化,并确保每个专门化提供
base
所需的所有成员。

使用traits的一个小缺点是,您必须为每个派生属性声明一个班级。您可以编写一个不那么冗长和繁重的变通方法,如下所示:

template <template <typename> class Derived, typename T>
class base {
public:
    typedef T value_type;
    value_type foo() {
        return static_cast<Derived<T>*>(this)->foo();
    }
};

template <typename T>
class Derived : public base<Derived, T> {
public:
    typedef T value_type;
    value_type foo() {
        return T(); //return some T object (assumes T is default constructable)
    }
};

int main() {
    Derived<int> a;
}
模板
阶级基础{
公众:
类型定义T值_类型;
值\类型foo(){
返回static_cast(this)->foo();
}
};
模板
派生类:公共基{
公众:
类型定义T值_类型;
值\类型foo(){
return T();//返回一些T对象(假设T是默认可构造的)
}
};
int main(){
导出了一个;
}

在C++14中,您可以删除
typedef
并使用函数
auto
返回类型扣除:

template <typename derived_t>
class base {
public:
    auto foo() {
        return static_cast<derived_t*>(this)->foo();
    }
};
模板
阶级基础{
公众:
自动foo(){
返回static_cast(this)->foo();
}
};

这是因为
base::foo
返回类型的推导被延迟到
派生的\u t
完成。

需要较少样板文件的类型特征的替代方法是将派生类嵌套在保存typedef(或使用)的包装类中并将包装器作为模板参数传递给基类

template <typename Outer>
struct base {
    using derived = typename Outer::derived;
    using value_type = typename Outer::value_type;
    value_type base_func(int x) {
        return static_cast<derived *>(this)->derived_func(x); 
    }
};

// outer holds our typedefs, derived does the rest
template <typename T>
struct outer {
    using value_type = T;
    struct derived : public base<outer> { // outer is now complete
        value_type derived_func(int x) { return 5 * x; }
    };
};

// If you want you can give it a better name
template <typename T>
using NicerName = typename outer<T>::derived;

int main() {
    NicerName<long long> obj;
    return obj.base_func(5);
}
模板
结构基{
使用派生=类型名外部::派生;
使用value\u type=typename外部::value\u type;
值类型基函数(int x){
返回静态_cast(this)->派生的_func(x);
}
};
//outer保存我们的typedef,derived保存其余的
模板
结构外部{
使用值_type=T;
派生结构:公共基{//outer现在已完成
值\u类型派生的\u func(int x){return 5*x;}
};
};
//如果你愿意,你可以给它取个更好的名字
模板
使用NicerName=typename外部::派生;
int main(){
尼塞尔奈;
返回对象基本函数(5);
}

我知道这基本上是您发现的并且不喜欢的解决方法,但我想记录它,并且说它基本上是这个问题的当前解决方案

我一直在寻找一种方法来做到这一点,但从来没有找到一个好的解决办法。 这是不可能的,这就是为什么像
boost::iterator\u facade
这样的东西最终需要很多参数的原因

当然,我们希望这样的事情能够奏效:

template<class CRTP> 
struct incrementable{
    void operator++(){static_cast<CRTP&>(*this).increment();}
    using ptr_type = typename CRTP::value_type*; // doesn't work, A is incomplete
};

template<class T>
struct A : incrementable<A<T>>{
    void increment(){}
    using value_type = T;
    value_type f() const{return value_type{};}
};

int main(){A<double> a; ++a;}
模板
可递增结构{
void操作符++(){static_cast(*this).increment();}
使用ptr_type=typename CRTP::value_type*;//无效,A不完整
};
模板
结构A:可递增


缺点是派生类中的trait必须使用限定的
typename
访问,或者使用
重新启用

正如您所知,codepad.org可以为您编译和运行代码,我相信它使用的是gcc/g++。因此,您永远不会脱离g++:)您能添加您遇到的错误,以便我对读者有用。@Seth:Ideone肯定使用gcc,所以它是另一个:)@Seth:谢谢您提供有关codepad.org的提示@斯利拉姆:打得好。我添加了它们。我创建了一个测试文件并编译了OP的代码,在Ubuntu g++4.4.1中添加了main(),效果很好。声明一个像
Derived
这样的对象会出错,我正在试图找出原因?@iammilind这是因为在一个空的
main()
no templat中
template<class CRTP, class ValueType> 
struct incrementable{
    void operator++(){static_cast<CRTP&>(*this).increment();}
    using value_type = ValueType;
    using ptr_type = value_type*;
};

template<class T>
struct A : incrementable<A<T>, T>{
    void increment(){}
    typename A::value_type f() const{return typename A::value_type{};}
//    using value_type = typename A::value_type;
//    value_type f() const{return value_type{};}
};

int main(){A<double> a; ++a;}