You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何std::conditional会拒绝T&?如何正确结合二者使用?

解决std::conditional结合void与T&的编译错误

想要实现模板参数为void时返回void,为其他类型T时返回T&,编写了如下代码:

#include<type_traits>

template<class T>
struct Foo {
    using X = std::conditional<std::is_void_v<T>, void, T&>::type;

    X bar(){ }
};

int main(){
    Foo<void> foo;
    return 0;
}

使用g++-13 --std=c++20 main.cpp或clang++ --std=c++20 main.cpp编译时出现错误:

main.cpp:5:58: error: cannot form a reference to 'void'
    5 |     using X = std::conditional<std::is_void_v<T>, void, T&>::type;
      |                                                          ^
main.cpp:11:15: note: in instantiation of template class 'Foo<void>' requested here
   11 |     Foo<void> foo1;
      |               ^
1 error generated.

报错原因

std::conditional的两个模板参数分支都会被编译器实例化检查,即使其中一个分支不会被选中。当T为void时,第二个分支的T&会被解析为void&,而C++标准明确禁止创建void的引用类型,因此触发编译错误。

正确实现方式

方法一:利用标准库的std::add_lvalue_reference

C++标准库中std::add_lvalue_reference的行为恰好符合需求:对void类型返回void,对其他类型返回对应的左值引用。直接使用即可:

#include<type_traits>

template<class T>
struct Foo {
    using X = std::add_lvalue_reference_t<T>;

    X bar(){ }
};

int main(){
    Foo<void> foo;
    Foo<int> foo2;
    return 0;
}

方法二:自定义模板特化

如果需要更明确的逻辑控制,可以通过模板特化实现辅助结构:

#include<type_traits>

// 通用模板:返回T&
template<typename T>
struct ref_or_void {
    using type = T&;
};

// void特化:返回void
template<>
struct ref_or_void<void> {
    using type = void;
};

template<class T>
struct Foo {
    using X = typename ref_or_void<T>::type;

    X bar(){ }
};

int main(){
    Foo<void> foo;
    Foo<int> foo2;
    return 0;
}

方法三:延迟实例化分支类型

通过将T&包装在另一个模板中,延迟其实例化时机,避免void场景下的非法类型检查:

#include<type_traits>

template<typename T>
struct add_lref {
    using type = T&;
};

template<class T>
struct Foo {
    using X = typename std::conditional<std::is_void_v<T>,
                                        std::type_identity_t<void>,
                                        add_lref<T>>::type::type;

    X bar(){ }
};

int main(){
    Foo<void> foo;
    Foo<int> foo2;
    return 0;
}

这里利用std::type_identity(C++20引入)保持void类型,而add_lref<T>只有在条件为真时才会被访问::type,从而避免void场景下实例化add_lref<void>。

内容的提问来源于stack exchange,提问作者chabapok

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 21:42:43