1

想象下一个无法编译的代码:

在线尝试!

#include <type_traits>
#include <iostream>

int main() {
    struct A { int i = 123; };
    struct B { int j = 456; };
    B x;
    if constexpr(std::is_same_v<decltype(x), A>)
        std::cout << "A: " << x.i;
    else if constexpr(std::is_same_v<decltype(x), B>)
        std::cout << "B: " << x.j;
}

通过这段代码,我希望有几个不同类型的代码分支。一般来说,我想要不同的分支不仅适用于某些类型,而且适用于任何 constexpr 条件。

上面的代码是不可编译的,因为看起来编译器总是试图编译所有 if-constexpr 分支,即使它们有编译时错误条件。

当然,我可以通过使用模板结构专业化来解决上述任务,如下面的可编译代码:

在线尝试!

#include <type_traits>
#include <iostream>

template <size_t Id>
struct Code;

template <>
struct Code<0> {
    template <typename AT>
    void operator()(AT & x){
        std::cout << "A: " << x.i;
    }
};

template <>
struct Code<1> {
    template <typename BT>
    void operator()(BT & x){
        std::cout << "B: " << x.j;
    }
};

int main() {
    struct A { int i = 123; };
    struct B { int j = 456; };
    B x;
    Code<std::is_same_v<decltype(x), A> ? 0 : std::is_same_v<decltype(x), B> ? 1 : -1>()(x);
}

但是最后一个解决方案有几个缺点 - 1)它更罗嗦,需要更多的代码行。2)它需要全局定义代码结构,因为模板结构只能全局定义。3) 它需要所有需要的参数才能使代码工作以传递/转发给 operator() 调用。

constexpr 变体看起来更优雅,使用起来更直观。有没有办法用 if-constexpr 解决这样的任务?强制编译器不编译 compile-time-false-branch。

4

1 回答 1

1

正如评论中提到的,“你必须使丢弃的语句依赖于模板参数” ——如果不引入模板,你想要做的事情是不可能的。

例如,这将“有效”,但远非一个好的解决方案。我将其添加为答案,因为与我标记为重复的问题的相似性存在争议。

#include <type_traits>
#include <iostream>

int main() {
    struct A { int i = 123; };
    struct B { int j = 456; };
    B x;
    
    [](auto const & x) {
        if constexpr(std::is_same_v<std::remove_cvref_t<decltype(x)>, A>) {
            std::cout << "A: " << x.i;
        } else if constexpr(std::is_same_v<std::remove_cvref_t<decltype(x)>, B>) {
            std::cout << "B: " << x.j;
        }
    }(x);
}
于 2020-12-30T14:49:33.210 回答