类型转换或转发的功能(取决于输入类型)

时间:2015-05-22 19:30:13

标签: c++ templates c++11 gcc

我有一段代码可以做这样的事情:

void some_func(SomeType st) {
    some_stuf...
    dosomething( st.myStruct() );
    some_more_stuff...
}

SomeType::myStruct的类型为MyStruct。这个SomeType经历了一些序列化,而在通信渠道的另一端,我得到了反序列化的SomeType,它被称为AlmostSomeType,它具有相同的字段,除了myStruct是键入std::string(无法将其反序列化为MyStruct)。

MyStruct可以从std::string创建。

现在,为了不创建some_func的其他版本(DRY!),我将会这样做:

template< typename Type >
void some_func( Type type ) {
    some_stuf...
    dosomething( getMyStruct( type.myStruct() ) ); 
    // or even something like: 
    const MyStruct& myStruct = getMyStruct( type.myStruct() );
    more calls to myStruct...
    some_more_stuff...
}

getMyStruct看起来像这样:

template< typename T >
T getMyStruct( T&& aT )
{ return aT; }

MyStruct getMyStruct( std::string myStructString )
{ return MyStruct( myStructString ); }

现在这就是我所知道的想法:

  1. 我知道它看起来并不好看,但现实生活中的项目并不好看。我无法修改AlmostSomeTypeSomeType
  2. 我不想创建任何额外的开销,这就是为什么我使用通用引用来处理任何类型的MyStruct(引用,const引用等)和{{1用于字符串的版本。
  3. 缺陷?如果std::string的参数构造函数不是MyStruct,有人会将std::stringgetMyStruct中的任何内容添加到MyStruct中,它可能会通过。
  4. 我已经完成了explicit的简单测试,其中包含所有需要的ctors和赋值运算符,编译后的代码为MyStruct,得到了我预期的结果,即没有复制ctor。
  5. 如果这是正确的方法,我想听听你的意见,即如果这个功能模板方法是正确的,或者我应该注意一些警告。我知道我在编译器优化方面有点重要,但是嘿!你不能只依赖语言语义。

    环境:gcc(4.7.2), - std = c ++ 11,-O2

    修改

    我正在使用的一些示例代码:

    -O2

    我得到的输出:

    struct MyStruct
    {
        MyStruct() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
        explicit MyStruct( std::string a ) : dummy_(a.size()) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
        MyStruct( const MyStruct& aOther ) : dummy_(aOther.dummy_) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
        MyStruct( MyStruct&& aOther ) : dummy_(std::move(aOther.dummy_)){ std::cout << __PRETTY_FUNCTION__ << "\n"; } 
        ~MyStruct() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
        MyStruct& operator=( const MyStruct& aOther ) { std::cout << __PRETTY_FUNCTION__ << "\n"; return *this; }
        MyStruct& operator=( MyStruct&& aOther ) { std::cout << __PRETTY_FUNCTION__ << "\n"; return *this; }
    
        double dummy_;
        char cdummy_[100];
    };
    
    struct MyAggregate
    {
        MyStruct myStruct_;
        std::string myString_;
    
        const MyStruct& myStruct() { return myStruct_; }
        const std::string& myString() { return myString_; }
    
        MyAggregate() :myString_("four") { myStruct_.dummy_ = 5.5; }
    };
    
    
    int main()
    {
        MyAggregate myAggregate;
        std::cout << "---\n";
        const MyStruct& ms1 = getMyStruct( myAggregate.myStruct_ );
        std::cout << "---\n";
        const MyStruct& ms2 = getMyStruct( myAggregate.myString_ );
        std::cout << "---\n";
        const MyStruct& ms3 = getMyStruct( myAggregate.myStruct() );
        std::cout << "---\n";
        const MyStruct& ms4 = getMyStruct( myAggregate.myString() );
        std::cout << "---\n";
        return 0;
    }
    

1 个答案:

答案 0 :(得分:0)

在解决方案中有过多的字符串副本(当您按值传递时)。为什么不提取字符串的特殊情况然后单独处理它?<​​/ p>

template<typename T, typename = 
   typename enable_if<!is_same<decay_t<T>,string>::value>::type >
decltype(auto) getMyStruct( T&& aT )
{ return aT; }

template<typename T, typename = 
    typename enable_if<is_same<decay_t<T>,string>::value>::type >
MyStruct getMyStruct (T &&aT)
{ return MyStruct (aT);}

我在上面删除了一些std::前缀,以使代码看起来更整洁。

在GCC 5.1上的输出是:

MyStruct::MyStruct()
---
decltype(auto) getMyStruct(T&&) [with T = MyStruct&; <template-parameter-1-2> = void]
---
MyStruct getMyStruct(T&&) [with T = std::__cxx11::basic_string<char>&; <template-parameter-1-2> = void]
MyStruct::MyStruct(std::__cxx11::string)
---
decltype(auto) getMyStruct(T&&) [with T = const MyStruct&; <template-parameter-1-2> = void]
---
MyStruct getMyStruct(T&&) [with T = const std::__cxx11::basic_string<char>&; <template-parameter-1-2> = void]
MyStruct::MyStruct(std::__cxx11::string)
---
MyStruct::~MyStruct()
MyStruct::~MyStruct()
MyStruct::~MyStruct()

我使用~/x86-toolchain-5.1/bin/g++ mystr.cpp --std=c++14

编译