构造函数上的模板和隐式转换防护

时间:2014-03-17 20:44:00

标签: c++ templates

我有一个模板类Foo,类型为T.当我创建T的实例时,我想确保构造函数传递相同的类型。

除了隐式转换的细节外,编译器确保了这一点。我想阻止这些,我无法弄清楚是否有一个好方法。编译器标志不是一个选项。

我实际上试图阻止从double到float的隐式转换,因为我的Foo类正在做一些有趣的魔法,炸毁了所谓的演员。有什么建议吗?

template <typename T>
class Foo {
public:
  explicit Foo(const T& x) {kBitCount = sizeof(T); }
  size_t kBitCount;
  size_t mySize(){ return kBitCount; } // Size used to demonstrate
};


int main(int argc, char *argv[])
{
  short sh = 5;
  Foo<int> foo_int_from_short(sh); // I want this to fail
  std::cout  << "size:" << foo_int_from_short.mySize() << std::endl; // prints 4

  Foo<short> foo_sh((unsigned int)5); // I want this to fail
  std::cout  << "size:" << foo_sh.mySize() << std::endl; // Prints 2

  return 0;
}

更新了解决方案,C ++ 11允许编译时检查

#include <limits>
#include <typeinfo>

#if __cplusplus > 199711L // If C++11 or greater
#include <type_traits>
#endif

template <typename T>
class Foo {
 public:
#if __cplusplus > 199711L
  // Prevent implict type conversions at compile time
  template<
       typename U,
       typename = typename std::enable_if< std::is_same<U, T >::value >::type
    >
  explicit Foo(const U& x)
  {
#else
  template< typename U >
  explicit Foo(const U& x)
  {
    // Assert on implict type conversions, run time
    if(typeid(U).name() != typeid(T).name())
    {
      std::cerr << "You're doing an implicit conversion with Foo, Don't" << std::endl;
      assert(typeid(U).name() == typeid(T).name()); // Or throw

    }
#endif

  }

2 个答案:

答案 0 :(得分:5)

如何添加额外的模板化构造函数来收集不太专业的调用:

template <typename T>
class Foo {
public:
    template<typename U>
    explicit Foo(const U& x);    // Undefined reference error at link time

    explicit Foo(const T& x) { kBitCount = sizeof(T); }
    // ...
};

如果您正在使用C ++ 11,则不必创建丑陋的未定义外部错误 - 您只需使用= delete

template<typename U>
explicit Foo(const U& x) = delete;

答案 1 :(得分:1)

Cameron解决方案的替代方案有一个构造函数,如果使用了错误的类型,它在编译时会失败:

template <typename T>
class Foo {
public:
    template<
       typename U,
       typename = typename std::enable_if<std::is_same<U, T>{}>::type
    >
    explicit Foo(const U& x) { ... }
};

可以使用几个标准别名缩短。