簡體   English   中英

在參數列表中使用std :: enable_if

[英]Using std::enable_if in a parameters list

在C ++中,請考慮以下示例:

template <typename first, typename... params> struct q;

template <typename first> struct q <first>
{
    q()
    {
        cout<<"x"<<endl;
    }
};

template <typename first, typename... params> struct q
{
    q()
    {
        cout<<"x";
        q <params...> ();
    }
};

int main()
{
    q <int, int> ();
    q <int, int, enable_if<true, bool>::type> ();
    // q <int, int, enable_if<false, bool>::type> ();
}

我定義了一個模板結構,可以接受任意數量的參數。 然后,我用一組參數實例化它。 每個構造函數都將構建一個新的q,除第一個參數外,其所有參數都將生成。 僅帶有一個參數的q將不再調用任何遞歸。

每次調用aq的構造函數時,它將打印出一個“ x”。 因此,main的第一行將導致程序打印出“ xx”,而第二行將打印出“ xxx”,因為實際上已啟用enable_if。 現在,如果第三行使我的程序打印出“ xx”(即build aq),我將不勝感激。 可悲的是,我得到的是錯誤

No template named 'type' in std::enable_if <false, bool>

我該怎么做才能糾正我的例子並使之生效?

謝謝

您誤解了std::enable_if的使用。 (我們很多人都這樣做了)。 這導致您提出了一個技術上被誤導的問題,而不是您想回答的更一般的問題。 您想回答的問題是僅基於編譯時條件,我的模板如何使用或忽略模板參數? ,這還不錯。

你有印象std::enable_if<Cond,T>::type是一個模板表達式來實例化TCondtrue ,並會實例化沒事的時候Cond是假的。

Condtrue ,這是正確的,因為std::enable_if<true,T>的定義如下:

std::enable_if<true,T> {
    typedef T type;
};

但是std::enable_if<false,T>的定義如下:

std::enable_if<false,T> {};

在這里查看這些定義

因此std::enable_if<false,T>::type不會消失 對於任何T ,它將變為格式不正確,不可編譯的引用,該引用引用的成員typestd::enable_if<false,T> (不存在)。 它成為編譯器錯誤。

因此, std::enable_if可用於基於某個布爾常量的編譯時值使模板類或函數的實例化成為可能或不可能。 並且由於編譯器會忽略模板的任何不可行的實例化(如果有可行的替代方案),因此,基於這種條件,它可用於在模板類或函數的替代實現之間進行編譯時選擇,例如

template<bool Cond>
typename std::enable_if<Cond,int>::type foo(int i) // A
{
    return i*i;
}

template<bool Cond>
typename std::enable_if<!Cond,int>::type foo(int i) // B
{
    return i + i;
}

在這里,如果some_bool_constanttrue ,則foo<some_bool_constant>(i)將產生i平方,如果some_bool_constanttrue ,則i會加倍 ,因為在第一種情況下B重載具有some_bool_constant false實例化,在第二種情況下A重載變為病態的。

替代重載使編譯器在每次看到foo<some_bool_constant>(x)時都可以考慮實例化的選擇,一個依賴於some_bool_constant的真值,一個不正確,另一個可行。 它選擇在每種情況下都可行的一個。 此行為稱為SFINAE ,這是您需要先了解std::enable_if

但是您沒有其他實例化:

q <int, int, enable_if<false, bool>::type> ()

“取決於false的值”。 false無條件表示false ,因此這只是格式錯誤的代碼。

並考慮:即使std::enable_if<false,bool>::type 莫名其妙地消失,這將留下:

q <int, int, > ()

仍然是錯誤的形式。

我該怎么做才能糾正我的例子並使之生效?

實際上,這並不需要很多,並且std::enable_if不起作用。 讓我們解決一個真正的問題: 僅基於編譯時條件,我的模板如何使用或忽略模板參數?

您需要以這樣的方式定義您的模板q<First, ... Rest>和其他一些模板accept_if<bool Cond, typename T> ,以便對q任何實例化:

/*(Iq)*/    q<A0,....,Aj,....,Ak>  // 0 <= j <= k

其中Aj = accept_if<some_bool_constant,t>::type ,則如果some_bool_constant == true(Iq)將具有與以下效果完全相同的效果:

q<A0,....,t,....,Ak>

如果some_bool_constant == false(Iq)將具有與以下相同的效果:

q<A0,....,Ak>

無需借助some_bool_constant任何運行時測試 (在(Iq)中 ,'....'只是可能的參數的示意圖占位符:與C ++壓縮包或省略號無關。)

但是accept_if<some_bool_constant,t>::type必須在編譯時解析為某種類型說明符 ,否則代碼accept_if<some_bool_constant,t>::type不正確。 它無法解決。 因此,在false情況下,它必須解析為類型說明符,該類型說明符將(Iq)的實例處理為不指定data-type

現在,擁有類型說明符的引人注目的實用程序在C / C ++中沒有指定任何數據類型 ,這早在很久以前就被認可為C的第一個ANSI標准。該類型說明符是void

從您的評論中,我們了解到q的模板參數代表一系列數據類型,構造函數的實例應從參數傳遞的源中提取出一系列數據類型。 在那種情況下, void理想地適合作為類型說明符,表示什么都不要做 您不能聲明一個void對象,更不用說從某個地方提取一個void對象了。

因此,我建議定義您的accept_if

template<bool Cond, typename T>
using accept_if = std::conditional<Cond,T,void>::type;

accept_if<true,T> = Taccept_if<false,T> = void 了解有關std :: conditional的信息

有了這個定義,您只需要再增加一個現有q專長即可:

template<> struct q<void> {};

q<void>一個不執行任何操作的默認構造函數。 這是一個類似您自己的但格式正確的示例程序,它說明了此解決方案:

#include <type_traits>
#include <iostream>

template<bool Cond, typename T>
using accept_if = typename std::conditional<Cond,T,void>::type;

template <typename first, typename... params> struct q;

template<> struct q<void> {};

template <typename first> struct q <first>
{
    q()
    {
        std::cout << "x" << std::endl;
    }
};

template <typename first, typename... params> struct q
{
    q()
    {
        std::cout << "x";
        q<params...>();
    }
};

int main()
{
    q<int, int>();
    q<int, int, accept_if<true,bool>>();
    q<int, int, accept_if<false,bool>>();
    return 0;
}

輸出是您想要的:

xx
xxx
xx

在不同的情況下,您甚至可能甚至希望在(Iq)中 忽略Aj = void 但是由於我們可以隨意創建類型,因此您始終可以創建與模板必須忽略的所有類型完全不同的類型,例如: struct ignore {}; 然后,您將定義:

template<bool Cond, typename T>
using accept_if = std::conditional<Cond,T,ignore>::type;

並專長:

template<> struct q<ignore> {};

enable_if用於在可以使用SFINAE的上下文中使用,這意味着在模板內部。

在非模板上下文(或不依賴模板參數的上下文)中,當條件為false時,引用enable_if<false, T>::typeenable_if<false, T>::type因為該成員不存在。

我該怎么做才能糾正我的例子並使之生效?

我不明白您要做什么。 您期望enable_if<false, bool>::type是什么? 沒有這樣的類型,您認為如何使用它?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM