函数模板或泛型 lambda 的废弃 if-constexpr 实例化中存在依赖名称错误

问题描述 投票:0回答:1

根据我的理解,依赖名称查找在模板实例化之前不会发生,并且废弃的if-constexpr语句中的模板调用不会被实例化。因此,我希望由于缺少依赖名称而格式错误的模板或泛型 lambda 只要仅在废弃的 if-constexpr 语句中使用,就不会产生编译错误。在某些情况下似乎就是这种情况。对于示例,取:

struct Struct {};
Struct s;

template<typename T>
void foo(T& s) {
    s.non_existing_member = 0;
}

struct A {
    template<typename T>
    void operator()(T& s) { // note 'void' return type
        s.non_existing_member = 0;
    }
};

struct B {
    template<typename T>
    auto operator()(T& s) { // note 'auto' return type
        s.non_existing_member = 0;
    }
};

正如预期的那样,这些不会产生编译错误:

if constexpr (false) {
    foo(s);
    A{}(s);
}

[](auto& s) {
    if constexpr (false) {
        s.non_existing_member = 0;
    }
}(s);

但是,这些确实如此,抱怨失踪的成员:

if constexpr (false) {
    auto bar = [](auto& s) {
        s.non_existing_member = 0;
    };

    // error: no member named 'non_existing_member' in 'Struct'
    bar(s); // note: in instantiation of function template specialization 'main()::(anonymous class)::operator()<Struct>'
    B{}(s); // note: in instantiation of function template specialization 'B::operator()<Struct>' requested here
}

我不太明白上述两种情况有什么不同。我在引用依赖类型名称时遇到类似的错误,例如

typename T::Type


重读文档(感谢@Jarod42):

在模板之外,对废弃的语句进行全面检查。 if constexpr 不能替代 #if 预处理指令。

如果 constexpr if 语句出现在模板化实体内部,并且 if 条件在实例化后不依赖于值,则在实例化封闭模板时不会实例化丢弃的语句。

我实际上预计

foo(s);
A{}(s);
也会编译失败。不过,最新的 clang、gcc 或 MSVC 都没有。我还希望以下内容能够发挥作用,它确实如此。完整示例

template<typename T>
void baz(T& s) {
    if constexpr (false) {
        s.non_existing_member = 0;
    }
}

struct C {
    template<typename T>
    auto operator()(T& s) {
        if constexpr (false) {
            s.non_existing_member = 0;
        }
    }
};

int main() {
    baz(s);
    C{}(s);
}
c++ templates lambda c++17 if-constexpr
1个回答
0
投票

你的程序格式不正确;一切都按预期进行。

案例1

if constexpr (false) {
    auto bar = [](auto& s) {
        s.non_existing_member = 0;
    };

    // error: no member named 'non_existing_member' in 'Struct'
    bar(s); // note: in instantiation of function template specialization 'main()::(anonymous class)::operator()<Struct>'
    B{}(s); // note: in instantiation of function template specialization 'B::operator()<Struct>' requested here
}

所有这些都直接位于

main
中,这意味着
if constexpr
基本上就像常规的
if
语句一样。参见 [stmt.if] p2:

在封闭模板化实体([temp.pre])的实例化过程中,如果条件在实例化后不依赖于值,则不会实例化丢弃的子语句(如果有)。

main
不是一个封闭模板,因此这个重要的句子不适用。
bar
的调用操作符被实例化并且语句

s.non_existing_member = 0;
对于

s

 类型的 
S
的格式不正确,它没有
non_existing_member

案例2

[](auto& s) {
    if constexpr (false) {
          s.non_existing_member = 0;
    }
}(s);

baz(s);
C{}(s);

这里,discarded statements内的代码没有被实例化,因为实际上有一个周围的模板。 也就是说,这个generic lambda的调用运算符隐式是一个函数模板。 当调用操作符被实例化时,

s.non_existing_member
并没有被实例化,因此不会导致错误。

© www.soinside.com 2019 - 2024. All rights reserved.