【发布时间】:2020-05-20 02:28:56
【问题描述】:
我想检查是否可以为给定类型实例化函数模板。以模板为例:
template<typename T> void f() { T{}; }
我想断言f<int> 是可实例化的,而f<S> 不是,其中S 是某种类型,如果实例化会导致f 的定义编译失败,比如:
struct S { ~S() = delete; };
显然,如果我知道函数体包含什么,我可以为每个语句编写单独的检查。但是,如果身体本身是未知的,这种方法将不起作用。
看来我不能使用通常的 sfinae 方法来执行此操作,因为没有检查函数体是否有推导失败。这是要玩的attempt。
确实,temp.deduct.8 似乎明确禁止这样做:
只有在函数类型、其模板参数类型及其显式说明符的直接上下文中的无效类型和表达式会导致推导失败。
“直接上下文”约束的原因似乎在下一个要点中:
注意:目的是避免要求实现处理涉及任意语句的替换失败。
如果我正确理解这一点,并且无法做到这一点,我能否解释一下为什么存在这个约束?我认为任意表达式可以被用户检查替换失败,那么为什么这对于实现来说太多了?
如果我对此有误解,并且是可能的,我可以解决这个问题吗?
【问题讨论】:
-
此约束存在的原因在您提出此问题之前立即引用的语句中进行了解释。而且,不,没有办法做到这一点,就像那样。 应该要做的是让模板函数本身,如果它的模板参数使用SFINAE来失败重载解析无法为特定类型实例化,可能类似于
template<typename T, typename=std::void_t<decltype(T{})>> void f()...。 -
@SamVarshavchik 这需要我更改函数本身。事实上,这个问题假设我什至不知道定义的内容,否则我只会分别对定义中的各个语句进行处理,而不更改函数。这导致,为什么一个实现不能做到这一点?
-
再一次,你引用的那句话已经解释了这一点。就是这样。这就是我们必须与之合作的。
-
好的,但如果是这样,我只是在问为什么它需要那样?似乎是一个合理的问题。
-
@cigien:编译器使用函数声明:返回值和参数(以及模板化函数的模板参数)。在做出所有决定之前,它不会考虑函数的主体(此时,当“最佳”选择无法实例化时,您将收到编译器错误)
标签: c++ language-lawyer sfinae