【问题标题】:How can I create a compile time assertion that a template is of specific types?如何创建模板属于特定类型的编译时断言?
【发布时间】:2012-01-20 18:35:07
【问题描述】:

我有一个模板函数,并希望在编译时确保它不会在特定类的子类型或超类型上实例化。

如果违反这一点,我怎么会导致 C++ 编译器错误?

class base {
};
class derived : public base {
};
class lowest : public derived {
};

template <typename T>
bool isCorrect(const T& obj) {
  typedef foo<T> D;
  foo<T> *def = foo<T>::find();
  return (def && def->getAnswer(object));
}

我希望 isCorrect 仅适用于 derived 类,但不适用于 baselowest。请注意,可能还有许多其他最低类和要排除的基类字符串以及可接受的替代派生类。

C++ 中有没有办法将模板限制为仅适用于我明确指定的派生类?

【问题讨论】:

标签: c++ templates compiler-errors


【解决方案1】:

类型特征,特别是is_base_of

#include <type_traits>

template <typename T>
bool isCorrect(const T& obj) {
  static bool const is_base = std::is_base_of<base, T>::value;
  static bool const derives = std::is_base_of<derived, T>::value;
  // specify allowed types here
  static bool const is_derived = std::is_same<T, derived>::value;
  // ---
  static_assert((!is_base && !derives) || is_derived, "wrong argument type");

  typedef foo<T> D;
  foo<T> *def = foo<T>::find();
  return (def && def->getAnswer(object));
}

请注意,这是特定于 C++11 的,但您可以使用 Boost.TypeTraits 获得相同的行为。

【讨论】:

    【解决方案2】:

    这是我知道的一种技术。

    首先,制作另一个模板类policy_enforcer。声明这个类不定义它,并为derived提供它的特化也定义了

    template<typename T> struct policy_enforcer;
    template<> struct policy_enforcer<derived> { };
    

    然后,在您希望锁定的函数中,包含表达式sizeof(policy_enforcer&lt;T&gt;)。由于不完整类型上的sizeof 是编译错误,这将阻止代码编译。

    更新了实时代码:using baseusing derivedusing lowest

    【讨论】:

    • 有点迟钝,但它会工作。希望有人会发布一种不那么晦涩的方式。
    【解决方案3】:

    您可以使用模板专业化。

    您只能为您希望能够使用的类型实现 isCorrect

    对于其他类型,您可以实现 dummy 方法,例如返回 false,或者根本不实现 isCorrect,在这种情况下,它不会为其他类型编译。

    #include <iostream>
    
    using namespace std;
    
    class base {
    };
    class derived : public base {
    };
    class lowest : public derived {
    };
    
    // using this it will fail if you try to pass anything
    // else than `derived`
    //  template <typename T>
    //     bool isCorrect(const T& obj);
    
    template <typename T>
    bool isCorrect(const T& obj) {
        cout << __PRETTY_FUNCTION__ << endl;
        return false;
    }
    
    template <>
    bool isCorrect<derived>(const derived& obj) {
        cout << __PRETTY_FUNCTION__ << endl;
        return true;
    //  typedef foo<derived> D;
    //  foo<derived> *def = foo<derived>::find();
    //  return (def && def->getAnswer(object));
    }
    

    测试:

    int main()
    {
        base b;
        derived d;
        lowest l;
    
        cout << isCorrect(b) << endl;
        cout << isCorrect(d) << endl;
        cout << isCorrect(l) << endl;
    }
    

    输出:

    bool isCorrect(const T&) [with T = base]
    0
    bool isCorrect(const T&) [with T = derived]
    1
    bool isCorrect(const T&) [with T = lowest]
    0
    

    【讨论】:

    • __func____FUNCTION____PRETTY_FUNCTION__ 等的 C++11 等价物。
    • 它不等价....首先,我看不到对 C++11 的任何要求,__PRETTY_FUNCTION__ 有什么问题,这不是问题的一部分,顺便说一句,谢谢信息:) ?使用__func____FUNCTION__,您只会得到isCorrectisCorrect&lt;derived&gt;,因此您看不到其他称为非专业版本的类型......
    • 没有错,我只是想提一下,因为 C++11 是当前的标准。大多数时候,其他所有东西(__FUNCTION____PRETTY_FUNCTION__ 等)都是非标准且不可移植的。 :)
    猜你喜欢
    • 2018-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-25
    相关资源
    最近更新 更多