【问题标题】:Is there a way to use SFINAE to detect whether a non-templated non-member function is not declared?有没有办法使用 SFINAE 来检测是否未声明非模板非成员函数?
【发布时间】:2015-09-17 13:43:56
【问题描述】:

我正在尝试使用 SFINAE 和 decltype 回答 this question。总而言之,发布者想要一个根据编译单元中是否声明另一个函数(无论是早于还是晚于相关函数声明)而行为不同的函数。

我尝试了以下方法:

auto some_function_2_impl(int) -> decltype(some_function_1(), void()) {
    cout << "Using some_function_1" << endl;
    some_function_1();
}

void some_function_2_impl(long) {
    cout << "Not using some_function_1" << endl;
}

void some_function_2() {
    return some_function_2_impl(0);
}   

但是,我收到以下错误消息:

main.cpp:4:60: error: 'some_function_1' was not declared in this scope
 auto some_function_2_impl(int) -> decltype(some_function_1(), void()) {

这就是重点,我想 - 我不希望定义 some_function_2_impl 的重载,因为 some_function_1 不存在。

我认为 SFINAE 可能需要模板才能工作,所以我尝试了以下方法(这可能有助于表明我不完全知道我在这里做什么):

template <int foo>
auto some_function_2_impl(int) -> decltype(some_function_1(), void()) {
    cout << "Using some_function_1" << endl;
    some_function_1();
}

template <int foo>
void some_function_2_impl(long) {
    cout << "Not using some_function_1" << endl;
}

但是,现在我收到以下错误:

main.cpp:5:60: error: there are no arguments to 'some_function_1' that 
depend on a template parameter, so a declaration of 'some_function_1'
must be available [-fpermissive]
 auto some_function_2_impl(int) -> decltype(some_function_1(), void()) {

我做错了什么?

【问题讨论】:

  • SFINAE 是替换失败不是错误:如果您的代码中没有前两个术语,则无法利用它。
  • @black:有没有办法将调用不存在的非模板化函数变成替换失败?
  • 你可以使用预处理器符号来区分
  • “定义”还是“声明”?它们的意思完全不同。
  • @T.C.:说得好,我的意思是声明

标签: c++ templates c++11 sfinae decltype


【解决方案1】:

即使在模板类型中,函数的查找也会立即完成,除了当根据模板参数类型存在可能的 ADL 查找时。

然后在替换类型后进行 ADL 查找。如果失败,则结果是替换失败。

由于您的函数调用不依赖于参数类型,因此该技术将不起作用。

我们仍然可以做一些适度有趣的事情:

template<class T, class...Ts>
struct first_two_match : std::false_type{};
template<class T, class...Ts>
struct first_two_match<T,T,Ts...>:std::true_type{}; // for standard compliance: If the only Ts... that match Ts... is nothing, program ill-formed.
struct secret_type_tag {};
template<class...Ts,
  std::enable_if_t<
    (sizeof...(Ts)==0) || first_two_match<secret_tag_type,Ts...>{}
  >* =nullptr
>
secret_type_tag some_function_1(Ts&&...);

template<bool b>
using bool_t=std::integral_constant<bool, b>;
static const auto some_function_defined = bool_t<
  !std::is_same<secret_tag_type, decltype( some_function_1() )>{}
>;

现在some_function_definedstd::true_type,如果some_function_1 的重载优先于我的some_function_1(Ts&amp;&amp;...)。由于some_function_1(Ts&amp;&amp;...) 的优先级非常低,因此任何“真正的”重载(也不是转发引用 glomer 并且采用 0 个参数)将是首选。

在更复杂的情况下,如果存在真正的重载,永远不会选择这样一个低优先级的重载。

这个仍然只是检测some_function_1是否在some_function_defined被创建的地方定义。骗子。

【讨论】:

    猜你喜欢
    • 2016-06-26
    • 2011-03-23
    • 2019-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多