【问题标题】:Templates and implicit conversion prevention on constructor构造函数上的模板和隐式转换预防
【发布时间】:2014-03-17 20:44:00
【问题描述】:

我有一个模板类 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

  }

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

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

    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;
    

    【讨论】:

    • 就可以了。我最终得到了一个 assert(typeid(U).name() == typeid(T).name(),它稍微破坏了通用部分并将事情推到运行时 - 但它有效。
    【解决方案2】:

    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) { ... }
    };
    

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

    【讨论】:

    • 这在 C++11 上运行良好,我最终得到 typename = typename std::enable_if::value >::type
    猜你喜欢
    • 2019-04-19
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-26
    相关资源
    最近更新 更多