【问题标题】:Template functions : mixing pass-by-copy & pass-by-reference模板功能:混合传递复制和传递引用
【发布时间】:2014-02-09 22:52:20
【问题描述】:

我有一个模板函数,负责将模板值写入流。它看起来像这样:

template < typename T >
void Write( T value, std::ostream& stream, endianness_t endian );

我已经实现了基本类型的版本:int、uint、float 等。 现在,如果我想写一个更复杂的结构,比如一个 std::string,我这样声明:

template<>
inline void Write( const std::string& value, std::ostream& stream, endianness_t endian ) { // Notice the reference
...
}

如果不显式调用“按引用传递”版本,我就无法调用它:

Write( strValue, stream, LITTLE_ENDIAN ); // error : tries to call Write<std::string>, undefined
Write< const std::string& >( strValue, stream, LITTLE_ENDIAN ); // OK, Write<const std::string&> is properly defined

问题在于,它对于我想要做的事情来说太冗长了。

然后我的问题是:如何让编译器猜测我想要使用的版本是“按引用传递”的版本?

我是否必须更改我的模板函数以获取 const 引用?如果是这样,我可以专门针对原始类型使用“pass-by-copy”吗?

【问题讨论】:

    标签: c++ templates pass-by-reference pass-by-value


    【解决方案1】:

    您应该更喜欢重载而不是模板专业化,我认为这样做可以解决您的问题:

    inline void Write( const std::string& value, std::ostream& stream, endianness_t endian ) {
        // ...
    }
    

    我还建议您返回并更改您为int 提到的所有专业化,并将内容改为重载。

    【讨论】:

    • 额外问题:如果我按顺序定义 Write(int64) 和 Write(int32) 是否存在风险,当我通过 32 位 int 时将使用 Write(int64) ?跨度>
    • @Takhiarel 适用于重载的正常规则。如果传递 32 位 int,则将选择需要最少转换的重载(即,如果有,则为 32 位重载)。
    【解决方案2】:

    不要为您想使用的每种可能的类型提供重载。这首先打破了使用通用代码的逻辑。话虽如此,为每种类型提供特化的需要可能指出这不是模板最成功的应用,更不用说弄乱函数模板特化不是最漂亮的选择as Sutter says

    因为您需要在互斥类型(内置和非内置)之间进行逻辑分离,所以这里有一个替代方案:

    template<class T>
    typename std::enable_if< std::is_fundamental<T>::value >::type foo_func(T arg)
    {
        std::cout << "Call for built in types" << std::endl;
    }
    template<class T>
    typename std::enable_if< !std::is_fundamental<T>::value >::type foo_func(T  const &arg)
    {
        std::cout << "Call for non built in types" << std::endl;
    }
    

    在这里解释代码发生了什么:

    1) std::is_fundamental 将在编译时返回 false 或 true ,具体取决于 T 是用户定义的还是内置类型。

    2) std::enable_if 将“允许”在第一种情况下为 true 和在第二种情况下为 false 声明函数模板,因此不会出现解析问题发生。

    3) 因此,当为内置类型调用 f​​oo_func 时,将使用第一个版本,并且 T(int、float 等)按值传递(对于内置类型来说更快)并且......你可以成像在另一种情况下会发生什么。

    【讨论】:

      【解决方案3】:

      您可以更改通用模板以通过 const ref 传递:

      template < typename T >
      void Write( const T& value, std::ostream& stream, endianness_t endian );
      

      【讨论】:

      • 这可能是一个解决方案,但这样做不会对原始类型造成性能损失吗?
      • @Takhiarel:这是个好问题。我假设Write 函数足够小且足够简单,可以自动内联。然后编译器将使间接消失。
      猜你喜欢
      • 2013-10-26
      • 2015-06-07
      • 2021-11-12
      • 2015-03-12
      • 1970-01-01
      • 2014-12-21
      • 1970-01-01
      • 2013-11-21
      • 1970-01-01
      相关资源
      最近更新 更多