最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++std::enable_if_t 與 std::is_same_v使用

 更新時間:2026年05月19日 09:06:08   作者:點(diǎn)云SLAM  
本文主要介紹了C++std::enable_if_t 與 std::is_same_v使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

1. 概念速覽

  • std::enable_if_t<B, T>:當(dāng)布爾條件 B 為 true 時,別名為類型 T;當(dāng) B 為 false 時替換失敗(SFINAE),用于在模板實(shí)例化階段啟用或禁用模板/函數(shù)重載。
  • std::is_same<T, U>:類型等價檢測。std::is_same_v<T, U> 是它的布爾快捷變量模板(true 或 false),用于在編譯期判斷兩個類型是否相同。

2.std::enable_if/std::enable_if_t— 定義與工作原理

標(biāo)準(zhǔn)定義

  • std::enable_if 是一個類模板(在 <type_traits> 中),常見形式:
template<bool B, class T = void>
struct enable_if { /* empty */ };

template<class T>
struct enable_if<true, T> { using type = T; };
  • std::enable_if_t<B,T> 是 C++14 引入的別名模板,等價于 typename std::enable_if<B,T>::type。

工作原理(SFINAE)

  • SFINAE = Substitution Failure Is Not An Error。當(dāng)替換模板參數(shù)導(dǎo)致一個類型/表達(dá)式無效時,編譯器不報錯而是將該模板從重載候選中移除。
  • 把 enable_if 放在模板參數(shù)列表或返回類型上,能在模板實(shí)例化階段根據(jù)條件決定該模板是否“可用”。

典型位置

  • 返回類型位置(不太推薦)
template<typename T>
std::enable_if_t<std::is_integral_v<T>, int> foo(T);
  • 模板參數(shù)位置(更常見,更穩(wěn)?。?/strong>:
template<typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
int foo(T);
  • 函數(shù)默認(rèn)參數(shù)位置(一種常見技巧):
template<typename T>
int foo(T, std::enable_if_t<std::is_integral_v<T>, int> = 0);

3.std::is_same/std::is_same_v— 定義與用途

定義

  • std::is_same<T,U> 是一個繼承自 std::true_type 或 std::false_type 的類模板,用來在編譯期判斷兩個類型是否相同(嚴(yán)格相同,const / volatile / 引用 等也會影響結(jié)果,除非用 std::remove_cv_t / std::decay_t 等預(yù)處理)。
  • std::is_same_v<T,U>(C++17)是 std::is_same<T,U>::value 的簡寫。

例子

static_assert(std::is_same_v<int, int>);        // true
static_assert(!std::is_same_v<int, const int>); // false
static_assert(std::is_same_v<int&, int&>);      // true

常見變體

常常和類型變換工具組合使用:

std::is_same_v<std::decay_t<T>, std::vector<int>>

表示“把 T 去掉引用與 cv 后是否為 std::vector”。

4.enable_if常見用法與示例

下面給出多種工程中常見的使用方式,說明優(yōu)劣與原因。

4.1 函數(shù)模板重載(按類型類別選擇實(shí)現(xiàn))

#include <type_traits>

template<typename T>
std::enable_if_t<std::is_integral_v<T>, T> twice(T x) { return x + x; }

template<typename T>
std::enable_if_t<std::is_floating_point_v<T>, T> twice(T x) { return x + x; }
  • 當(dāng) T 為整型,第一候選有效;當(dāng) T 為浮點(diǎn)數(shù),第二候選有效。
  • 如果兩個條件都 false,編譯器找不到匹配重載 -> 錯誤。

4.2 把enable_if放在模板參數(shù)位置(更推薦)

template<typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
T twice(T x) { return x + x; }

優(yōu)點(diǎn):返回類型干凈,錯誤信息更好,避免某些重載解析奇怪的問題。

4.3 作為構(gòu)造函數(shù)/模板構(gòu)造器的限制

限制模板構(gòu)造函數(shù)只在特定 T 下可用,防止與拷貝構(gòu)造沖突:

struct S {
    S() = default;

    template<typename T, typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, S>>>
    S(T&& x) { /* ... */ }
};

用途:防止模板構(gòu)造器被當(dāng)作拷貝/移動構(gòu)造器,導(dǎo)致意外刪除默認(rèn)構(gòu)造/拷貝等。

4.4 類模板偏特化的啟用(工廠/traits 場景)

template<typename T, typename Enable = void>
struct Processor;

// 只有當(dāng) T 是容器(例如有 value_type)時啟用
template<typename T>
struct Processor<T, std::void_t<typename T::value_type>> {
    static void process(const T& c) { /* ... */ }
};

上面結(jié)合了 std::void_t 的檢測方式(常和 enable_if 搭配實(shí)現(xiàn)偏特化/重載選擇)。

4.5 作為 constexpr if 的替代(在 C++17 之前)

在 C++11/14 中,經(jīng)常用 enable_if 做在編譯期選擇不同實(shí)現(xiàn)。C++17 的 if constexpr 更好用。

5.is_same_v常見用法與示例

5.1 精確類型匹配

template<typename T>
void f() {
    if constexpr (std::is_same_v<std::decay_t<T>, double>) { /* double specialization */ }
    else { /* fallback */ }
}

5.2 防止模板構(gòu)造器捕獲拷貝構(gòu)造

與上面 enable_if 示例類似,也常用于 static_assert

template<typename T>
S(T&&) {
    static_assert(!std::is_same_v<std::decay_t<T>, S>, "use copy ctor");
    // ...
}

5.3 類型分支:dispatch / traits 匹配

template<typename T>
using is_string = std::is_same<std::decay_t<T>, std::string>;

template<typename T>
std::enable_if_t<is_string<T>::value, void>
doit(T&& s) { /* handle string */ }

6. 典型組合示例(共同使用)

下面是一個真實(shí)場景:一個 from_json 泛型函數(shù),對不同參數(shù)類型選擇不同實(shí)現(xiàn)(整數(shù)->直接 parse,容器->元素按遞歸解析)。

#include <type_traits>
#include <vector>
#include <string>

template<typename T>
std::enable_if_t<std::is_integral_v<T>, T>
from_json(const std::string& s) {
    // parse integer
}

template<typename T>
std::enable_if_t<std::is_same_v<T, std::string>, T>
from_json(const std::string& s) {
    return s;
}

template<typename T>
std::enable_if_t<!std::is_same_v<T, std::string> && std::is_class_v<T>, T>
from_json(const std::string& s) {
    // fallback for class types
}

說明:

  • 使用 std::is_same_v 精確匹配字符串類型;
  • enable_if_t<!std::is_same_v<...>> 實(shí)現(xiàn)否定條件;
  • 注意邏輯優(yōu)先級與可讀性,復(fù)雜組合應(yīng)用 if constexpr(C++17)或 concepts(C++20)替代。

7. 常見陷阱與調(diào)試技巧

陷阱 A:把enable_if放在返回類型可能導(dǎo)致難讀錯誤或二義性

示例:

template<typename T>
std::enable_if_t<cond1, void> f(T);

template<typename T>
std::enable_if_t<cond2, void> f(T);

cond1cond2 同時為 true(或都為 false),可能導(dǎo)致二義性或無匹配。把 enable_if 放在模板參數(shù)位置更明確。

陷阱 B:std::is_same對const/ 引用 / cv 修飾敏感

std::is_same_v<int, const int> == false
std::is_same_v<int, int&> == false

解決:在比較前統(tǒng)一使用 std::decay_t / std::remove_cv_t / std::remove_reference_t

陷阱 C:與重載解析的交互

當(dāng)你寫多個 enable_if 重載時,務(wù)必檢查它們互相排斥(即只有一個在給定類型下為真),否則會出現(xiàn)編譯器報告二義性。

陷阱 D:啟用/禁用構(gòu)造函數(shù)時要小心拷貝/移動語義

模板構(gòu)造函數(shù)能奪取拷貝構(gòu)造函數(shù)的位置,導(dǎo)致編譯器不生成默認(rèn)拷貝構(gòu)造或移動構(gòu)造。常用 std::enable_if<!std::is_same...> 來防止模板構(gòu)造器與拷貝構(gòu)造器沖突。

調(diào)試技巧

  • 使用 static_assert 打印條件:static_assert(std::is_integral_v<T>, "T must be integral");
  • 編譯器錯誤信息繁雜時,先把復(fù)雜的 enable_if 條件抽成別名模板并單獨(dú) static_assert 檢查。
  • typeid(T).name() 在運(yùn)行時查看實(shí)際類型(僅用作調(diào)試,編譯期問題仍然需要 static_assert)。

8.enable_if的簡化實(shí)現(xiàn)

下面是 enable_ifis_same 的簡化版實(shí)現(xiàn)(便于理解):

// 簡化 enable_if
template<bool B, typename T = void>
struct my_enable_if { /* empty; substitution failure leads to SFINAE */ };

template<typename T>
struct my_enable_if<true, T> { using type = T; };

template<bool B, typename T = void>
using my_enable_if_t = typename my_enable_if<B,T>::type;


// 簡化 is_same
template<typename A, typename B>
struct my_is_same : std::false_type {};

template<typename A>
struct my_is_same<A,A> : std::true_type {};

template<typename A, typename B>
inline constexpr bool my_is_same_v = my_is_same<A,B>::value;

這正是標(biāo)準(zhǔn)庫實(shí)現(xiàn)思路(還有一些額外優(yōu)化 / 輔助宏 / constexpr)。

9. 遷移到 C++20:concepts / requires / if constexpr

C++20 引入了 Concepts,讓很多 enable_if 用法顯得冗余,示例如下。

用requires或concept替代enable_if

#include <concepts>

template<typename T>
concept Integral = std::is_integral_v<T>;

template<Integral T>
T twice(T x) { return x + x; }

// 或者
template<typename T>
T twice(T x) requires std::is_integral_v<T> { return x + x; }

優(yōu)勢:

  • 可讀性強(qiáng)、編譯器錯誤信息友好;
  • 直接把約束放在模板簽名,避免 SFINAE 的復(fù)雜性。

用if constexpr減少enable_if的使用

template<typename T>
void f(T t) {
    if constexpr (std::is_integral_v<T>) { /* integral path */ }
    else { /* non-integral */ }
}

一般原則:

  • 新項目優(yōu)先使用 Concepts;
  • if constexpr 在函數(shù)體內(nèi)部做編譯期分支;
  • 只在需要選擇“是否啟用/暴露不同重載”的場景下才用 enable_if,并盡量把它放在模板參數(shù)位置以保持清晰。

10. 總結(jié)

  1. 優(yōu)先選擇 C++20 concepts / requires / if constexpr;它們比 enable_if 更直觀、錯誤信息更好。

  2. 在必須使用 enable_if 時:

    • 把 std::enable_if_t 放在模板參數(shù)位置(template<typename T, typename = std::enable_if_t<cond>>)或用默認(rèn)參數(shù);
    • 避免把 enable_if 放在返回類型上(除非你確實(shí)了解代價與行為)。
  3. 使用 std::is_same_v 時要小心 cv/ref 修飾,通常在比較前 std::decay_t / std::remove_cvref_t。

  4. 遇到復(fù)雜條件時,把條件抽成 using 別名或 constexpr bool 幫助調(diào)試與復(fù)用。

  5. 對構(gòu)造函數(shù)的模板化與 enable_if 使用要格外小心(避免吞掉拷貝/移動構(gòu)造器)。

  6. 若用的是 C++17,可以用 if constexpr 簡化很多場景;若能用 C++20,則用 concepts 替代 enable_if。

附:示例

示例 A:按類型啟用不同實(shí)現(xiàn)(返回類型位)

#include <type_traits>
#include <iostream>

template<typename T>
std::enable_if_t<std::is_integral_v<T>, T> twice(T x) { return x + x; }

template<typename T>
std::enable_if_t<std::is_floating_point_v<T>, T> twice(T x) { return x + x; }

int main(){
    std::cout << twice(3) << "\n";   // ok
    std::cout << twice(1.5) << "\n"; // ok
    // twice(std::string("a")); // compile error
}

示例 B:防止模板構(gòu)造器吞噬拷貝構(gòu)造(常見)

#include <type_traits>

struct S {
    S() = default;
    S(const S&) = default;

    template<typename T, typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, S>>>
    S(T&&) { /* convert */ }
};

示例 C:C++20 concepts 版本(等價)

#include <concepts>

template<std::integral T>
T twice(T x) { return x + x; }

到此這篇關(guān)于C++std::enable_if_t 與 std::is_same_v使用的文章就介紹到這了,更多相關(guān)C++ std::enable_if_t std::is_same_v內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言中#pragma?once的作用

    C語言中#pragma?once的作用

    這篇文章主要介紹了C語言中#pragma?once的作用,pragma once 一般由編譯器提供保證,更多相關(guān)內(nèi)容在下面文章詳細(xì)展開需要的小伙伴可以參考一下
    2022-05-05
  • C++結(jié)構(gòu)體字節(jié)對齊示例

    C++結(jié)構(gòu)體字節(jié)對齊示例

    這篇文章主要為大家介紹了C++結(jié)構(gòu)體字節(jié)對齊示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • C語言之實(shí)現(xiàn)字符串小寫變大寫的實(shí)例

    C語言之實(shí)現(xiàn)字符串小寫變大寫的實(shí)例

    這篇文章主要介紹了C語言之實(shí)現(xiàn)字符串小寫變大寫的實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • C語言 以字符形式讀寫文件詳解及示例代碼

    C語言 以字符形式讀寫文件詳解及示例代碼

    本文主要介紹C語言 以字符形式讀寫文件,這里整理了讀寫文件的一些資料并附示例代碼,供大家學(xué)習(xí)參考,有需要的小伙伴可以參考下
    2016-08-08
  • C指針原理教程之C快速入門

    C指針原理教程之C快速入門

    C語言作為大學(xué)編程或者計算機(jī)專業(yè)的一門必修課,把很多初學(xué)編程的小伙伴都難住了,感覺無從下手,今天呢,我們來簡單介紹下,如何快速入門C語言
    2019-02-02
  • C++線程親和性優(yōu)化指南分享

    C++線程親和性優(yōu)化指南分享

    線程親和性通過綁定線程到特定CPU核心,減少遷移開銷,提升緩存命中率和性能,適用于多核、NUMA架構(gòu),實(shí)現(xiàn)方式包括Linux的pthread庫和Windows的API,需注意負(fù)載均衡、超線程及系統(tǒng)拓?fù)?建議結(jié)合工具驗(yàn)證效果
    2025-09-09
  • 深入了解C語言中的const和指針

    深入了解C語言中的const和指針

    這篇文章將具體為大家介紹一下C語言中const和指針的使用,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)const和指針有一定幫助,需要的可以參考一下
    2022-02-02
  • C++從文件中提取英文單詞的實(shí)現(xiàn)方法

    C++從文件中提取英文單詞的實(shí)現(xiàn)方法

    本文主要介紹了C++從文件中提取英文單詞的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • C++ windows LOG4plus的使用小結(jié)

    C++ windows LOG4plus的使用小結(jié)

    這篇文章主要介紹了C++ windows LOG4plus的使用小結(jié),本文通過圖文示例代碼相結(jié)合給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-05-05
  • C++實(shí)現(xiàn)一行一行讀取文本的方法

    C++實(shí)現(xiàn)一行一行讀取文本的方法

    今天小編就為大家分享一篇C++實(shí)現(xiàn)一行一行讀取文本的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07

最新評論

汉川市| 禹城市| 曲周县| 饶平县| 黄陵县| 山西省| 响水县| 柳州市| 襄樊市| 博爱县| 苍溪县| 华阴市| 渭南市| 象州县| 兰溪市| 西乌珠穆沁旗| 巫溪县| 沂源县| 大石桥市| 额济纳旗| 拉萨市| 庆城县| 泰和县| 宁陕县| 东山县| 同仁县| 山阴县| 华坪县| 东阳市| 丽江市| 宁化县| 怀集县| 延安市| 五常市| 河南省| 云安县| 田林县| 华蓥市| 柞水县| 新竹县| 黄大仙区|