功能模板:外部模板与显式专业化 [英] Function templates: extern template vs explicit specialisation

查看:74
本文介绍了功能模板:外部模板与显式专业化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下函数模板声明:

Consider the following function template declaration:

template <typename T, typename = std::enable_if_t<std::is_same_v<T, int>>>
void foo(T i);

此模板只有一个可能的有效实例,即使用T = int.我想将此定义放在实现文件中.我可以想到两种可能的方式. (如果您想知道为什么我会这样做而不是只说void foo(int i),那是因为模板版本可防止在调用站点进行隐式转换.)

There is only one possible valid instantiation of this template, namely with T = int. I'd like to put this definition in an implementation file. I can think of two possible ways of doing so. (If you're wondering why on earth I'd do this rather than just saying void foo(int i), it's because the template version prevents implicit conversions at the call site.)

方法1:

我可以使用extern template声明来告诉其他TU foo<int>()在其他地方实例化:

I can use an extern template declaration to tell other TUs that foo<int>() is instantiated elsewhere:

// In foo.hpp
template <typename T, typename = std::enable_if_t<std::is_same_v<T, int>>>
void foo(T i);

extern template void foo(int);

// In foo.cpp
template <typename T, typename>
void foo(T i) { ... } // full template definition

template void foo(int); // explicit instantiation with T = int

方法2:

对于int情况,我可以提供明确的专业化条件:

I can provide an explicit specialisation for the int case:

// In foo.hpp
template <typename T, typename = std::enable_if_t<std::is_same_v<T, int>>>
void foo(T i);

template <> void foo(int i); // explicit specialisation declaration (*)

// In foo.cpp
template <>
void foo(int i) { ... } // explicit specialisation definition

问题:

  • 这两种方法都合法吗,还是我无意中依赖UB?
  • 如果两种方法均合法,那么除了方法2的键入量稍微少一点的事实之外,是否有充分的理由偏爱一种方法而不是另一种方法?无论哪种方式,GCC和Clang都可以很好地工作.
  • 对于方法2,实际上是否需要(*)处的显式专门化声明?同样,如果省略了GCC和Clang,它们都会非常高兴,但是这样做使我不感到满意,因为在另一个TU中对foo(3)的调用是模板的隐式实例化,没有可见的定义,并且也不保证定义存在于其他地方.
  • Are both of these approaches legal, or am I unintentionally relying on UB?
  • If both are legal, is there a good reason to prefer one approach over the other, other than the fact that approach 2 is very slightly less typing? Both GCC and Clang work equally well with either approach.
  • For approach 2, is the explicit specialisation declaration at (*) actually required? Again, both GCC and Clang are perfectly happy if it's omitted, but doing so makes me uncomfortable about the fact that a call to foo(3) in another TU is an implicit instantiation of a template with no definition visible, and no promise that such a definition exists elsewhere.

推荐答案

第三种方法.在方法3中,指定要具有的功能,然后添加模板重载并将其标记为delete.看起来像

There is a third approach. In approach 3 you specify the function you want to have and the you add a template overload and mark that as delete. That looks like

void foo(int i)
{
    // stuff
}

template <typename T>
void foo(T t) = delete;

由于模板版本将完全匹配所有类型,因此除int以外,在所有情况下都将首选该版本,因为非模板完全匹配优于模板.因此,您将只能使用int调用foo,而所有其他类型将给您一个错误,他们正在尝试调用已删除的函数void foo(T t).

Since the template version will match all types exactly it will be preferred in all cases except int since a non template exact match is preferred to a template one. So you will only be able to call foo with an int and all other types will give you an error that they are trying to call the deleted function void foo(T t).

在线示例

这篇关于功能模板:外部模板与显式专业化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆