区分用户类型和原语

Differentiate between user type and primitives

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

我试过重载二元运算符,但这只是说 'user types'...

没有合适的重载
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();
//}

像 (class test, 3.4, "string") 这样的输入的预期结果是 "test3.4string"

我觉得std::is_class可以代替你的IsAUserType

https://en.cppreference.com/w/cpp/types/is_class

您可以将单个参数函数一分为二,然后使用 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

原始数据类型包括 integer 、 character 、 void 、 float 等。它们已经在语言中定义,即用户可以使用这些数据类型而无需在语言中定义它们。 用户定义的数据类型是用户在使用它们时或之前必须定义的数据类型。