c++ - 区分用户类型和原语

标签 c++ c++11 templates types usertype

我试图在可变参数模板中区分用户类型和原始类型。

我试过重载二元运算符,但这只是说“用户类型”没有合适的重载...

template <typename T>
void PrintParams(T t)
{
    if (IsAUserType)
        std::cout << typeid(t).name();
    else
                std::cout << t;
}

    template <typename First, typename... Rest>
void PrintParams(First first, Rest... rest)
{
    if (IsAUserType)
        std::cout << typeid(first).name();
    else
                std::cout << first;

    PrintParams(rest...);
}

    // If you know what to do with this, then that would also be very helpful...
    //Overload << operator for user types
//template <typename T>
//friend std::ostream& operator<< (std::ostream& os, T t)
//{
            // 
    //if (std::is_fundamental<t>::value)
        //std::clog << t;
    //else
        //std::clog << typeid(t).name();
//}

输入(类测试,3.4,“字符串”)的预期结果将是 “test3.4字符串”

最佳答案

您可以将单个参数函数一分为二,然后使用 SFINAE 根据参数是否为基本类型来启用正确的函数:

template<typename T, typename std::enable_if<std::is_fundamental<T>::value, int>::type = 0>
void PrintParams(T t) {
    std::cout << t;
}

template<typename T, typename std::enable_if<!std::is_fundamental<T>::value, int>::type = 0>
void PrintParams(T t) {
    std::cout << typeid(t).name();
}

template<typename First, typename... Rest>
void PrintParams(First first, Rest... rest) {
    PrintParams(first);  // ... and call the single argument version here
    std::cout << ",";
    PrintParams(rest...);
}

另一种方法是使用 operator<< 检查类型是否支持流式传输而不是检查它是否是基本类型。这将使流式处理适用于类(如 std::string 和用户定义的类)。

#include <iostream>
#include <type_traits>
#include <typeinfo>
#include <utility>
// SFINAE support

namespace detail {
    template<class>
    struct sfinae_true : std::true_type {};

    template<class S, class T>
    static auto test_lshift(int)
        -> sfinae_true<decltype(std::declval<S>() << std::declval<T>())>;

    template<class S, class T>
    static auto test_lshift(long) -> std::false_type;
} // namespace detail

template<class T>
struct has_ostream : decltype(detail::test_lshift<std::ostream, T>(0)) {};
// using the SFINAE support stuff

template<typename T, typename std::enable_if<has_ostream<T>::value, int>::type = 0>
void PrintParams(const T& t) {
    std::cout << "Type: " << typeid(t).name() << "\n"
              << " supports operator<<   Value = " << t << "\n";
}

template<typename T, typename std::enable_if<!has_ostream<T>::value, int>::type = 0>
void PrintParams(const T& t) {
    std::cout << "Type: " << typeid(t).name() << "\n"
              << " does NOT support operator<<\n";
}

template<typename First, typename... Rest>
void PrintParams(First first, Rest... rest) {
    PrintParams(first);
    PrintParams(rest...);
}
// example classes

class Foo { // will not support streaming
    int x = 5;
};

class Bar { // this should support streaming
    int x = 10;
    friend std::ostream& operator<<(std::ostream&, const Bar&);
};

std::ostream& operator<<(std::ostream& os, const Bar& b) {
    return os << b.x;
}
// testing

int main() {
    int i = 2;
    Foo f;
    Bar b;
    std::string s = "Hello world";

    PrintParams(i, f, b, s);
}

可能的输出:

Type: i
 supports operator<<   Value = 2
Type: 3Foo
 does NOT support operator<<
Type: 3Bar
 supports operator<<   Value = 10
Type: NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
 supports operator<<   Value = Hello world

关于c++ - 区分用户类型和原语,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57746801/

相关文章:

c++ - 为 SDL 事件过滤创建指向成员函数的非常量指针

c++ - 模板成员函数和非模板重载的参数推导

c++ - 从静态成员函数推断类模板参数的模式

c++ - 为什么这个使用未签名产品的简单功能不起作用?

c++ - 使用&符号后跟下划线命名的变量是什么意思?

c++ - 如何直接从构造函数结束 C++ 代码?

c++ - 我如何确定模板参数参数是否是模板内结构中另一个类的实例? C++

c++ - SFINAE 适用于扣除但因替代而失败

c++ - 在同一实现下模板化 T 和 T&

c++ - 在不同的数据类型之间交替