c++隐藏魔法: 那些鲜为人知的奇淫技巧

c++隐藏魔法: 那些鲜为人知的奇淫技巧

1.通过 std::enable_if 实现条件模板实例化

std::enable_if 可以帮助你根据类型特征启用或禁用特定的模板函数。它是C++中一种非常强大的SFINAE(Substitution Failure Is Not An Error)技巧,能够根据传入的类型条件选择函数重载。 示例:

#include <iostream>
#include <type_traits>

template <typename T>
typename std::enable_if<std::is_integral<T>::value>::type print(T value) {
    std::cout << "Integral: " << value << std::endl;
}

template <typename T>
typename std::enable_if<std::is_floating_point<T>::value>::type print(T value) {
    std::cout << "Floating point: " << value << std::endl;
}

int main() {
    print(42);       // 输出 Integral: 42
    print(3.14);     // 输出 Floating point: 3.14
}

通过 2.std::move_iterator 优化容器间的转移操作

std::move_iterator 可以在遍历容器时避免不必要的拷贝,通过移动元素来提高效率。这在大量数据移动(而非拷贝)时非常有用。

#include <iostream>
#include <vector>
#include <iterator>
#include <string>

int main() {
    std::vector<std::string> src = {"1", "2", "3", "4"};
    std::vector<std::string> dest;
    dest.reserve(src.size());

    std::move_iterator<std::vector<std::string>::iterator> begin(src.begin());
    std::move_iterator<std::vector<std::string>::iterator> end(src.end());
    std::copy(begin, end, std::back_inserter(dest));

    for (auto& x : src) {
        std::cout << x << " ";  // 
    }
    
    for (auto& x : dest) {
        std::cout << x << " ";  // 输出 1 2 3 4
    }
}

使用 3.std::source_location 提供丰富的调试信息

C++20引入了 std::source_location,它允许在程序运行时获取代码的文件名、行号和函数名等信息。你可以用它来方便地调试,特别是在日志输出时提供详细的源代码信息。

#include <iostream>
#include <source_location>

void log(const std::string& message, const std::source_location location = std::source_location::current()) {
    std::cout << "File: " << location.file_name()
              << ", Line: " << location.line()
              << ", Function: " << location.function_name() << "\n"
              << message << std::endl;
}

int main() {
    log("An error occurred!");
}

通过 4.std::tuple 和 std::index_sequence 实现变参模板优化

std::tuple 和 std::index_sequence 允许你在模板中传递和操作多个参数。通过结合这些工具,可以实现变参模板的高效处理,特别是在需要逐一操作每个参数时。

#include <iostream>
#include <tuple>
#include <utility>

// 用来打印单个元组元素
template <typename Tuple, std::size_t... Indices>
void print_tuple(const Tuple& t, std::index_sequence<Indices...>) {
    // 展开每个索引,调用 std::get<Indices>(t) 获取元组的元素
    (..., (std::cout << std::get<Indices>(t) << " ")); // C++17 的折叠表达式
}

// 对外接口:隐藏了索引生成的逻辑
template <typename... Args>
void print(Args&&... args) {
    // 创建元组,自动生成索引序列,并调用 print_tuple
    print_tuple(std::make_tuple(std::forward<Args>(args)...), 
                std::index_sequence_for<Args...>{});
}

int main() {
    print(1, 2.5, "Hello", 'C'); // 输出:1 2.5 Hello C
    return 0;
}

5.在模板元编程中使用if constexpr进行编译时switch

#include <iostream>
#include <type_traits>

template <typename T>
void printType(T value) {
    if constexpr (std::is_integral_v<T>) {
        std::cout << "Integer: " << value << '\n';
    } else if constexpr (std::is_floating_point_v<T>) {
        std::cout << "Float: " << value << '\n';
    } else {
        std::cout << "Other: " << value << '\n';
    }
}

int main() {
    printType(42);        // Integer
    printType(3.14);      // Float
    printType("C++!");    // Other
}

6.SFINAE:检测类是否有某成员函数

通过 SFINAE(Substitution Failure Is Not An Error)机制,可以检测某个类是否有特定的成员函数。

#include <iostream>
#include <type_traits>

template <typename T>
class HasToString {
private:
    template <typename U>
    static auto test(int) -> decltype(std::declval<U>().toString(), std::true_type{});

    template <typename>
    static std::false_type test(...);

public:
    static constexpr bool value = decltype(test<T>(0))::value;
};

struct A {
    void toString() {}
};

struct B {};

int main() {
    std::cout << "A has toString: " << HasToString<A>::value << "\n"; // true
    std::cout << "B has toString: " << HasToString<B>::value << "\n"; // false
    return 0;
}

7.RAII:std::shared_ptr 自定义析构函数

可以利用 std::shared_ptr 的自定义析构函数,管理复杂资源,比如文件句柄、锁等。

#include <iostream>
#include <memory>
#include <cstdio>

struct FileDeleter {
    void operator()(FILE* file) const {
        if (file) {
            std::cout << "Closing file\n";
            fclose(file);
        }
    }
};

int main() {
    std::shared_ptr<FILE> file(fopen("example.txt", "w"), FileDeleter{});
    if (file) {
        fputs("Hello, World!", file.get());
    }
    return 0;
}

8.编译期计算:constexpr 求解递归问题

使用 constexpr 编写可以在编译期执行的递归算法。

constexpr int factorial(int n) {
    return (n <= 1) ? 1 : n * factorial(n - 1);
}

int main() {
    constexpr int result = factorial(5);
    std::cout << "Factorial of 5: " << result << "\n";
    return 0;
}

9.隐藏模板参数中的数据

通过类型参数“隐藏”编译期数据。

#include <iostream>

template <int N>
struct HiddenData {
    static constexpr int value = N;
};

template <typename T>
void reveal() {
    std::cout << "Hidden value: " << T::value << "\n";
}

int main() {
    reveal<HiddenData<42>>(); // 输出:Hidden value: 42
    return 0;
}

10. 编译期字符串计算

通过模板元编程,在编译期计算字符串的长度或其他属性。

#include <iostream>
#include <array>

template <std::size_t N>
constexpr std::size_t constexpr_strlen(const char (&str)[N]) {
    return N - 1; // 去掉 '\0'
}

int main() {
    constexpr auto len = constexpr_strlen("Hello, World!");
    static_assert(len == 13, "Length mismatch");
    std::cout << "Length: " << len << "\n";
    return 0;
}
全部评论

相关推荐

已注销:测开吗?网易给的有点少 建议干三个月跳槽 然后来一段一整年的大厂 然后再找一段大厂转正实习无敌了
点赞 评论 收藏
分享
评论
1
1
分享
牛客网
牛客企业服务