如何让这个模板类编译为类和基元类型?

时间:2011-10-30 12:00:37

标签: c++ templates

如何编译以下代码?

我意识到编译器对V<double>不满意,因为它试图为GetterFn编译我的typedef,但我希望GetterFnGetCalc() 可用于类,但忽略原始类型。

我应该如何重新编写这门课程?

#include <vector>

using namespace std;

class Bar
{
    public:
        float getMyFloat() const { return 42.5; }
};

template< typename T >
class V
{
    public:
        typedef float (T::*GetterFn)() const;
        void getCalc( std::vector<double>& vec, GetterFn fn ) const
        {
            vec.clear();
            for ( size_t i=0; i<m_v.size(); ++i )
                vec.push_back( m_v[ i ].*(fn)() );
        }

    private:
        vector<T> m_v;
};

int main(int argc, char** argv)
{
    V<Bar>    vb;  // ok
    V<double> vd;  // compiler not happy
}

3 个答案:

答案 0 :(得分:3)

Alf的回答确实是最简单的方式。不要让GetterFn成为成员函数指针,只需使用重载的自由函数来获取值:

void getCalc( std::vector<double>& vec) const
{
    vec.clear();
    for ( size_t i=0; i<m_v.size(); ++i )
        vec.push_back( get_value(m_v[ i ]) );
}

然后恰当地重载get_value

double get_value(double value) { return value; }

double get_value(Bar value) { return value.getMyFloat(); }

当然,强烈建议使用比get_value更具描述性的名称。

答案 1 :(得分:1)

double不能拥有会员功能。因此,使用非会员功能。

答案 2 :(得分:1)

如果不知道你想要为基本类型做什么,建议完整的解决方案有点困难。但是,我建议您使用std::is_fundamental类型特征。

如果您希望整个成员函数集合只是有条件地存在,那么将它们包装成成员助手类是一个想法:

#include <vector>
#include <type_traits>
#include <cstddef>

class Bar
{
public:
  float getMyFloat() const { return 42.5; }
};

template< typename T >
class V
{
private:

  static const bool m_primitive = std::is_fundamental<T>::value; // convenience

  template <bool B, typename U> struct Helper;

  template <typename U> struct Helper<false, U>
  {
    typedef float (T::*GetterFnType)() const;
    void getCalc(std::vector<double> & v1, std::vector<U> const & v2, GetterFnType f)
    {
      v1.clear();
      for (std::size_t i = 0; i < v2.size(); ++i)
        v1.push_back((v2[i].*f)());
    }
  };

public:

  // use Helper<m_primitive, T>::GetterFn and Helper<m_primitive, T>::getCalc() here

private:
  std::vector<T> m_v;
};

int main(int argc, char** argv)
{
  V<Bar>    vb;  // ok
  V<double> vd;  // compiler also happy
}

您可能还需要在实际实施中执行一些std::enable_if。如果您发布更多详细信息,我们可以详细说明。

如果你对更广泛的重新设计持开放态度,Konrad的回答感觉最终结果会更清晰,更简单,但我再次赞成复杂的模板伏都教: - )