【问题标题】:Disable template but allow specializations [duplicate]禁用模板但允许专业化[重复]
【发布时间】:2016-11-24 10:19:14
【问题描述】:

例如,我声明了一个通用模板:

template <class T>
void foo(T value);

但我需要每个类型的程序员都必须声明其专业化:

struct my_user_t
{
// ...
};

template <>
void foo<my_user_t>(my_user_t value) {
  // ...
}

// Somewhere in big program:
my_user_t my_value;
foo(my_value);

现在如果程序员忘记为他的用户类型专门化模板,链接器说它找不到符号,而不是编译器。所以在大程序中很难找到它在哪里使用。

我怎样才能像这样声明模板:

template <class T>
void foo(T value) {
    static_assert(???, "You must specialize foo<> for your type");
}

这样编译器(不是链接器)会说我在哪里错误地使用了foo(my_user_t)

【问题讨论】:

标签: c++ templates


【解决方案1】:

只是根据模板参数类型补一些东西:

template<typename T>
struct always_false : std::false_type {};

template <class T>
void foo(T value) {
    static_assert(always_false<T>::value , "You must specialize foo<> for your type");
}

或者,我认为您可以将默认函数模板声明为已删除:

template <class T>
void foo(T value)=delete;

【讨论】:

  • 对于足够聪明的编译器来说,这仍然是不正确的 NDR :)
  • 我明白了。自定义 totally_always_false&lt;T&gt; 特征会起作用吗,因为编译器无法确定我没有在某处对其进行专门化?
  • 是的,这几乎是典型的做法。
  • 是的,它有效,但两种变体都禁用了可转换类型的通用模板。例如,您对foo&lt;std::string&gt;() 有专门化,如果没有这个技巧,您实际上可以用const char * 调用它。但是有了这个技巧,它就会自动被禁用。有什么办法可以避免吗?
【解决方案2】:

这是一个使用 sizeof 的产品:

template<class T> void foo(T) {
    static_assert(sizeof(T) != sizeof(T), "You must specialize foo<> for your type");
}

【讨论】:

  • static_assert(false, "You must specialize foo&lt;&gt; for your type"); 有什么不同吗?
  • 是的。它有很大的不同。你自己看。你
  • 刚刚检查过,sizeof(T) != sizeof(T) 确实可以编译。所以它可以编译但没有满足这个模板的类型,因此实际上无法使用。非常聪明。 std::enable_if&lt;std::is_same&lt;T, T&gt;::value&gt;::type 对我来说更容易解释
【解决方案3】:

您可以使用函数重载而不是模板。 所以编译器至少必须看到它的声明,而程序员很可能不会忘记在为自己的类型添加声明后添加函数定义。

另一种方法是使用具有空类定义的类模板(该函数将成为成员函数)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-27
    • 1970-01-01
    • 2015-07-04
    • 1970-01-01
    • 2020-07-18
    • 2015-06-12
    • 2020-07-25
    相关资源
    最近更新 更多