【问题标题】:Function for type converting or forwarding (depending on input type)类型转换或转发的功能(取决于输入类型)
【发布时间】:2015-08-04 22:33:38
【问题描述】:

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

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

这个SomeType::myStruct 的类型是MyStruct。这个SomeType 经历了一些序列化,在通信通道的另一端我得到反序列化SomeType,它被称为AlmostSomeType,它具有相同的字段,除了myStruct 的类型是std::string(它不能' t 被反序列化为MyStruct)。

MyStruct 可以从std::string 创建。

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

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(参考、常量参考等)和 std::string 版本字符串。
  3. 缺陷?如果有人将MyStructstd::string 以外的任何内容放入getMyStruct,如果MyStruct 的参数构造函数不是explicit,它可能会通过。
  4. 我使用 MyStruct 进行了简单的测试,其中包含所有需要的 ctor 和赋值运算符,使用 -O2 编译代码并得到了我预期的结果,即没有调用任何复制 ctor。

我想听听你的意见,如果这是正确的方法,即如果这个函数模板方法是好的,或者有一些我应该注意的警告。我知道我在考虑编译器优化,但是,嘿!你不能只依赖语言语义。

环境:gcc (4.7.2),-std=c++11,-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;
}

我得到的输出:

MyStruct::MyStruct()
---
T getMyStruct(T&&) [with T = MyStruct&]
---
MyStruct getMyStruct(std::string)
MyStruct::MyStruct(std::string)
---
T getMyStruct(T&&) [with T = const MyStruct&]
---
MyStruct getMyStruct(std::string)
MyStruct::MyStruct(std::string)
---
MyStruct::~MyStruct()
MyStruct::~MyStruct()
MyStruct::~MyStruct()

【问题讨论】:

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


    【解决方案1】:

    您的解决方案中有过多的字符串副本(当您通过值传递时)。为什么不提取字符串的特殊情况,然后单独处理呢?

    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编译

    【讨论】:

    • 在我的情况下不是 RVO 吗?
    • RVO 是 return 价值优化。这就是我离开 MyStruct 临时按值返回的原因——没关系,RVO 有效。另一方面,按值传递 参数通常涉及复制。您可以尝试使用一些玩具类而不是字符串。
    猜你喜欢
    • 2018-01-19
    • 1970-01-01
    • 2020-06-02
    • 1970-01-01
    • 2016-04-19
    • 1970-01-01
    • 2014-11-13
    • 2010-11-13
    • 2020-07-26
    相关资源
    最近更新 更多