【问题标题】:Why can we have instances of type traits classes in C++?为什么我们可以在 C++ 中拥有类型特征类的实例?
【发布时间】:2021-02-25 11:38:45
【问题描述】:
#include <type_traits>

int main()
{
    std::decay<int()> p;
    static_assert(1 == sizeof(p));
    
    std::add_pointer<int> q;
    static_assert(1 == sizeof(q));
}

这是有效的。但是为什么我们需要decay 等实例呢?这使得拼写错误(decay 而不是decay_t 等)更难被发现。这些类不应该有私有或删除的构造函数吗?

【问题讨论】:

    标签: c++ templates constructor metaprogramming typetraits


    【解决方案1】:

    为什么不呢?有时有必要创建具有特征的对象,而不允许这样做会给一些人带来问题,而对其他人却没有实质性的好处。

    例如,您可以使用特征进行标签调度:

    #include <type_traits>
    #include <iostream>
    
    void foo(std::false_type) {
        std::cout << "this is the overload for std::false_type";
    }
    void foo(std::true_type) {
        std::cout << "this is the overload for std::true_type";
    }
    
    int main() {
        foo( std::is_same<int,double>{} );
    }
    

    调用者和函数都没有实际使用该对象,但必须对其进行实例化才能选择所需的重载。

    【讨论】:

    • 我认为更正常的情况是std::true_typestd::false_type 重载,并在调用站点实例化std::is_same&lt;X, Y&gt;
    • @Caleth 哦,对了,这是一个很好的例子。谢谢
    • 在这种情况下,我会将foo 设为函数模板并专门针对false_typetrue_type。不需要参数。
    • @not-a-user 你会,但是为什么你要禁止其他人在这种情况下使用标签调度? C++ 不会仅仅因为。按照同样的逻辑,我们应该禁止将bool 参数传递给函数,因为实现相同功能有不同的方法
    • @not-a-user 参见 here 以比较 SFINAE 与标签调度(实际上答案使用几乎相同的示例)。它们是互补的,有时一个更合适,有时另一个更合适,不允许一个是不好的
    【解决方案2】:

    为什么我们可以在 C++ 中拥有类型特征类的实例?

    因为类型特征是类模板,并且类可以被实例化,除非它们的构造函数被删除。

    事实上,Cpp17UnaryTypeTrait 和 Cpp17BinaryTypeTrait 是必需的/保证是 Cpp17DefaultConstructible。 Cpp17TransformationTrait 似乎没有这个要求/保证。

    【讨论】:

    • 是的,但是为什么呢?为什么决定不删除构造函数?你有提到的要求/保证的参考吗?
    • @not-a-user 这不是 C++ 的哲学,不允许让用户犯错误的事情(那是不同的语言)。当创建实例总是错误时,构造函数将被删除,但事实并非如此
    • @not-a-user Do you have a reference 参见标准部分 [meta.rqmts]。
    猜你喜欢
    • 1970-01-01
    • 2014-10-14
    • 1970-01-01
    • 2019-12-08
    • 1970-01-01
    相关资源
    最近更新 更多