如何创建模板具有特定类型的编译时断言?

时间:2011-12-15 00:42:57

标签: c++ templates compiler-errors

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

如果违反此规则,如何导致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 ++中是否有办法将模板限制为仅应用于我明确指定的派生类?

3 个答案:

答案 0 :(得分:9)

输入特征,特别是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获得相同的行为。

答案 1 :(得分:4)

这是我所知道的一种技术。

首先,制作另一个模板类policy_enforcer。声明此类而不定义,并为derived 提供已定义的的专门化:

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

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

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

答案 2 :(得分:1)

您可以使用模板专业化。

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

对于其他类型,您可以实现虚方法,例如返回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