C++ 模板的通用包装:优化机会

C++ 模板的通用包装:优化机会,c++,templates,generics,optimization,c++-cli,C++,Templates,Generics,Optimization,C++ Cli,我试图将模板与泛型结合起来,重点是尽可能快(合理地)访问基元/值类型的属性,最好将其保存在C++/CLR中。考虑这个简单的模板: template< typename type > class value_wrapper { public: type value; }; 模板 类值包装器{ 公众: 类型值; }; 及其对应方: generic< typename T > public ref class ValueWrapper { ... publi

我试图将模板与泛型结合起来,重点是尽可能快(合理地)访问基元/值类型的属性,最好将其保存在C++/CLR中。考虑这个简单的模板:

template< typename type >
class value_wrapper {
public:
    type value;
};
模板
类值包装器{
公众:
类型值;
};
及其对应方:

generic< typename T >
public ref class ValueWrapper {
    ...
public:
    property T Value {
        T get() {
            if( T::typeid == System::Int32::typeid )
                return ( T )( ( value_wrapper< int > * )ptr )->value;
            ...branches for some other types...
            // if all else fails:
            return ( T )( Object ^ )( ( value_wrapper< gcroot< Object ^ > > * )ptr )->value;
        }
        ...
    }
    ...
private:
    void *ptr;
};
generic
公共引用类ValueWrapper{
...
公众:
属性T值{
不明白{
if(T::typeid==System::Int32::typeid)
返回(T)((value_-wrapper*)ptr)->值;
…其他类型的分支。。。
//如果所有其他方法都失败:
返回(T)(Object^)((value_wrapper>*)ptr)->值;
}
...
}
...
私人:
无效*ptr;
};
问题1。当泛型的MSIL变成值类型的专门化时,代码是否进一步优化?是否可以在此处检查类型,例如,在
ValueWrapper
中,非int类型和类型比较本身的分支将被优化掉

现在,在每个方法中列出所有受支持的类型有点痛苦,因此我为此创建了一个单独的函数:

template< typename action, typename context_type >
__forceinline
static bool apply( System::Type ^type, void *value, System::Object ^*box, context_type context ) {
    if( type == System::Int32::typeid )
        return action().operator()< int >( ( int * )value, context ), true;
    ...branches for some other types...
    // if all else fails:
    return action().operator()< gcroot< System::Object ^ > >( box, context ), false;
}

struct get_value {
    template< typename type, typename result_type >
    void operator () ( result_type *result, void *ptr ) {
        *result = ( ( value_wrapper< type > * )ptr )->value;
    }
};

generic< typename T >
public ref class ValueWrapper {
    ...
    property T Value {
        T get() {
            T result;
            System::Object ^box;
            return apply< get_value >( T::typeid, &result, &box, ptr ) ? result : ( T )box;
        }
        ...
    }
    ...
};
模板
__强制内联
静态布尔应用(系统::类型^类型,无效*值,系统::对象^*框,上下文类型上下文){
if(type==System::Int32::typeid)
返回操作().operator()((int*)值,上下文),true;
…其他类型的分支。。。
//如果所有其他方法都失败:
返回操作().operator()>(框,上下文),false;
}
结构获取值{
模板
void运算符()(结果类型*result,void*ptr){
*结果=((value_wrapper*)ptr)->值;
}
};
通用
公共引用类ValueWrapper{
...
属性T值{
不明白{
T结果;
系统::对象^box;
返回apply(T::typeid,&result,&box,ptr)?result:(T)box;
}
...
}
...
};
事实证明,这大约比原始代码慢3倍

问题2。这里可以更改什么,以使优化器使第二个实现的速度更接近第一个实现(理想情况下,速度差在10%-20%之间)


另外,这主要是关于VC 2010的。但是,如果VC 2012在这方面有所不同,那也很高兴知道。

经过一些修补和MSIL的观察,我对第二个问题有了答案:只需传递
typeid
getter函数,而不是
typeid
本身。对于框架来说,在每次比较中请求类型信息似乎比将其存储到某个变量(旧的
type
参数)并重用它要容易得多

通过这种方法,经济放缓从3倍降至5-10%(!)

问题2已解决,问题1待定

生成的代码:

template< typename action, typename context_type >
__forceinline
static bool apply( System::Type ^type(), void *value, System::Object ^*box, context_type context ) {
    if( type() == System::Int32::typeid )
        return action().operator()< int >( ( int * )value, context ), true;
    if( type() == SupportedStruct::typeid )
        return action().operator()< SupportedStruct >( ( SupportedStruct * )value, context ), true;
    if( type() == System::String::typeid )
        return action().operator()< std::wstring >( ( System::String ^* )value, context ), true;
    // for both reference types and unknown value types:
    return action().operator()< gcroot< System::Object ^ > >( box, context ), false;
}

struct get_value {
    template< typename type, typename result_type >
    void operator () ( result_type *result, void *ptr ) {
        *result = ( ( value_wrapper< type > * )ptr )->value;
    }
    template< typename type >
    void operator () ( System::String ^*result, void *ptr ) {
        *result = gcnew System::String( ( ( value_wrapper< type > * )ptr )->value.c_str() );
    }
};

generic< typename T >
public ref class ValueWrapper {
    ...
public:
    property T Value {
        T get() {
            T result;
            System::Object ^box;
            return apply< get_value >( TypeGetter, &result, &box, ptr ) ? result : ( T )box;
        }
        ...
    }
    ...
private:
    void *ptr;
private:
    static System::Type ^TypeGetter() {
        return T::typeid;
    }
};
模板
__强制内联
静态布尔应用(System::Type^Type(),void*值,System::Object^*框,上下文类型上下文){
if(type()==System::Int32::typeid)
返回操作().operator()((int*)值,上下文),true;
if(type()==SupportedStruct::typeid)
返回操作().operator()((SupportedStruct*)值,上下文),true;
if(type()==System::String::typeid)
返回操作().operator()((系统::字符串^*)值,上下文),true;
//对于引用类型和未知值类型:
返回操作().operator()>(框,上下文),false;
}
结构获取值{
模板
void运算符()(结果类型*result,void*ptr){
*结果=((value_wrapper*)ptr)->值;
}
模板<类型名称类型>
void运算符()(系统::字符串^*结果,void*ptr){
*结果=gcnewsystem::String((value_wrapper*)ptr)->value.c_str();
}
};
通用
公共引用类ValueWrapper{
...
公众:
属性T值{
不明白{
T结果;
系统::对象^box;
返回apply(TypeGetter,&result,&box,ptr)?result:(T)box;
}
...
}
...
私人:
无效*ptr;
私人:
静态系统::类型^TypeGetter(){
返回T::typeid;
}
};

您可以通过使用
案例
获得一些速度。第二个实现比较慢,并且可能不会像第一个实现那样快,因为您首先构造一个
T
,然后分配给它。此外,您在堆栈上放置了一个
System::Object^
,尽管并非在所有情况下都需要它,而且函数调用可能会有一些开销。@stijn您的意思是
switch(T::typeid)
?我认为这是不可能的。至于第二个问题,我同意10%-20%的速度差,只是不是3倍。为清晰起见进行编辑。(另外:从理论上讲,内联可以帮助减少函数调用开销,检测不必要的
&删除它,并消除对
结果
的额外操作。这都是关于优化器的能力。)哎呀,很抱歉,打开typeid确实不起作用