模板类方法与重载方法冲突

时间:2009-12-10 09:43:42

标签: c++ templates

我在C ++中有一个模板类(有点简化):

template<typename T>
struct C
{
  T member;
  void set(const &T x) { member = x; }
  void set(int x) { member = x; }
};

正如您所看到的,set()函数可以被称为 ,类型为T,或者带有int。这工作正常,除非T是一个int,在这种情况下我得到一个模糊的转换错误。我明白为什么会这样,但有没有办法实现我想要的?

5 个答案:

答案 0 :(得分:2)

为int提供专业化:

template<>
struct C<int>
{
  int member;
  void set(int x) { member = x };
};

答案 1 :(得分:1)

解决此问题的一种方法是为int提供仅具有一个set函数的模板的特化。否则,您可能希望查看Boost库,如果模板元编程代码中的enable_if之类的内容允许您仅在T不是int类型时打开函数set(int x)

答案 2 :(得分:0)

你可以将调用转换为调用代码中的int或const int吗?

答案 3 :(得分:0)

这取决于你真正想做的事情。当您尝试从member设置T x时,您编写的示例没有多大意义,这是int。虽然有些情况可能有意义,但我怀疑你的真实代码中还有其他东西。

方法必须具有相同的名称吗?如果是这样的话? 专门针对int的struct有意义吗? 你有什么其他限制?

也许这对你有用:

template<typename T>
struct C
{
  T member;
  template<typename U>
  void set(const U& x) { member = x; }
  void set(int x) { member = x; }
};

现在set(int)重载set(const U&)set(const U&)接受非T参数,但在尝试分配给X时可能会失败。它可能允许比set( const T&)更多的转化。

如果这还不够好,添加extra level of indirection应该可以解决问题:

template<typename T>
struct C
{
  T member;
  void set(const T& x) { setInternal( x ); }

private:
  template<typename U>  
  void setInternal(const U& x) { member = x; }
  void setInternal(int x) { member = x; }
};

答案 4 :(得分:0)

您似乎只有在参数为 T int 时才能使set方法可用。但是,如果您只为 int 专门化C,则所有隐式转换仍然会发生,就像您没有尝试以特殊方式处理 int 类型一样。

如果你真的想要禁用隐式转换,一种方法是使用boost::enable_if - 只有满足条件才能使方法可用。

#include <boost/type_traits/is_same.hpp>
#include <boost/utility/enable_if.hpp>

template<typename T>
struct C
{
    T member;
    template <class U>
    typename boost::enable_if_c<
        boost::is_same<T, U>::value || boost::is_same<U, int>::value
    >::type
    set(const U& x) { member = x; }
};


int main()
{
    C<int> i;
    i.set(3.14); //error
    i.set(10);   //OK
    i.set('a');  //error

    C<double> d;
    d.set(3.14);  //OK
    d.set(3.14f); //error
    d.set(10);    //OK
    d.set('a');   //error
}

要在没有boost::enable_if(或自己实现)的情况下获得相同的结果,您可能还需要设置私有的所有不需要的版本(C ++ 0x也允许删除这些过载)。

template<typename T>
struct C
{
    T member;

    void set(const T& x) { member = x; }
    void set(int x) { member = x; }
private:
    template <class U>
    void set(const U&);
};

template <>
struct C<int>
{
    int member;
    void set(int x) { member = x; }
private:
    template <class U>
    void set(const U&);
};


int main()
{
    C<int> i;
    i.set(3.14); //error
    i.set(10);   //OK
    i.set('a');  //error

    C<double> d;
    d.set(3.14);  //OK
    d.set(3.14f); //error
    d.set(10);    //OK
    d.set('a');   //error
}

但是,为 int 设置此异常对我来说似乎相当随意。来自int的转换可能也不是特别安全,例如int->float可能会丢失大值的精确度,int->short / int->char / int->unsigned可能会溢出。