首頁 > 軟體

C++ Boost Parameter超詳細講解

2022-11-25 14:01:14

一、說明

Boost.Parameter 使得將引數作為鍵/值對傳遞成為可能。除了支援函數引數外,該庫還支援模板引數。 Boost.Parameter 在您使用長參數列並且引數的順序和含義難以記住時特別有用。鍵/值對使得以任何順序傳遞引數成為可能。因為每一個值都是通過一個鍵來傳遞的,所以各種值的含義也更加清晰。

二、範例程式碼

範例 53.1。作為鍵/值對的函數引數

#include <boost/parameter.hpp>
#include <string>
#include <iostream>
#include <ios>
BOOST_PARAMETER_NAME(a)
BOOST_PARAMETER_NAME(b)
BOOST_PARAMETER_NAME(c)
BOOST_PARAMETER_NAME(d)
BOOST_PARAMETER_NAME(e)
BOOST_PARAMETER_FUNCTION(
  (void),
  complicated,
  tag,
  (required
    (a, (int))
    (b, (char))
    (c, (double))
    (d, (std::string))
    (e, *)
  )
)
{
  std::cout.setf(std::ios::boolalpha);
  std::cout << a << 'n';
  std::cout << b << 'n';
  std::cout << c << 'n';
  std::cout << d << 'n';
  std::cout << e << 'n';
}
int main()
{
  complicated(_c = 3.14, _a = 1, _d = "Boost", _b = 'B', _e = true);
}

Example53.1

範例 53.1 定義了一個函數 complicated(),它需要五個引數。引數可以按任何順序傳遞。 Boost.Parameter 提供了宏 BOOST_PARAMETER_FUNCTION 來定義這樣的函數。

在可以使用 BOOST_PARAMETER_FUNCTION 之前,必須定義鍵/值對的引數。這是通過宏 BOOST_PARAMETER_NAME 完成的,它只是傳遞了一個引數名稱。該範例使用 BOOST_PARAMETER_NAME 五次來定義引數名稱 a、b、c、d 和 e。

請注意,引數名稱是在名稱空間標記中自動定義的。這應該避免與程式中的同名定義發生衝突。

定義引數名稱後,BOOST_PARAMETER_FUNCTION 用於定義函數 complicated()。傳遞給 BOOST_PARAMETER_FUNCTION 的第一個引數是返回值的型別。這在範例中是無效的。請注意,型別必須用括號括起來——第一個引數是 (void)。

第二個引數是正在定義的函數的名稱。第三個引數是包含引數名稱的名稱空間。在第四個引數中,存取引數名稱以進一步指定它們。

在範例 53.1 中,第四個引數以 required 開頭,這是一個使後面的引數成為必需的關鍵字。 required 後跟一對或多對,由引數名稱和型別組成。將型別括在括號中很重要。

各種型別用於引數 a、b、c 和 d。例如,a 可用於將 int 值傳遞給 complicated()。沒有為 e 給出型別。相反,使用星號,這意味著傳遞的值可以具有任何型別。 e 是一個模板引數。

將各種引數傳遞給 BOOST_PARAMETER_FUNCTION 後,定義函數體。像往常一樣,這是在一對大括號之間完成的。可以在函數體中存取引數。它們可以像變數一樣使用,在 BOOST_PARAMETER_FUNCTION 中分配型別。範例 53.1 將引數寫入標準輸出。

complicated() 是從 main() 呼叫的。引數以任意順序傳遞給 complicated()。引數名稱以下劃線開頭。 Boost.Parameter 使用下劃線來避免與其他變數名稱衝突。

注意:

要在 C++ 中將函數引數作為鍵/值對傳遞,您還可以使用命名引數習慣用法,它不需要像 Boost.Parameter 這樣的庫。

範例 53.2。可選功能引數

#include <boost/parameter.hpp>
#include <string>
#include <iostream>
#include <ios>
BOOST_PARAMETER_NAME(a)
BOOST_PARAMETER_NAME(b)
BOOST_PARAMETER_NAME(c)
BOOST_PARAMETER_NAME(d)
BOOST_PARAMETER_NAME(e)
BOOST_PARAMETER_FUNCTION(
  (void),
  complicated,
  tag,
  (required
    (a, (int))
    (b, (char)))
  (optional
    (c, (double), 3.14)
    (d, (std::string), "Boost")
    (e, *, true))
)
{
  std::cout.setf(std::ios::boolalpha);
  std::cout << a << 'n';
  std::cout << b << 'n';
  std::cout << c << 'n';
  std::cout << d << 'n';
  std::cout << e << 'n';
}
int main()
{
  complicated(_b = 'B', _a = 1);
}

BOOST_PARAMETER_FUNCTION 還支援定義可選引數。

在範例 53.2 中,引數 c、d 和 e 是可選的。這些引數使用可選關鍵字在 BOOST_PARAMETER_FUNCTION 中定義。

可選引數的定義類似於必需引數:引數名稱後跟型別。像往常一樣,型別被括在括號中。但是,可選引數需要有預設值。

通過呼叫 complicated(),僅傳遞引數 a 和 b。這些是唯一需要的引數。由於未使用引數 c、d 和 e,因此將它們設定為預設值。

除了 BOOST_PARAMETER_FUNCTION 之外,Boost.Parameter 還提供宏。例如,您可以使用 BOOST_PARAMETER_MEMBER_FUNCTION 來定義成員函數,並使用 BOOST_PARAMETER_CONST_MEMBER_FUNCTION 來定義常數成員函數。

您可以使用 Boost.Parameter 定義函數,嘗試自動為引數賦值。在這種情況下,您不需要傳遞鍵/值對——只傳遞值就足夠了。如果所有值的型別不同,Boost.Parameter 可以檢測出哪個值屬於哪個引數。這可能需要您對模板超程式設計有更深入的瞭解。

範例 53.3。作為鍵/值對的模板引數

#include <boost/parameter.hpp>
#include <boost/mpl/placeholders.hpp>
#include <type_traits>
#include <typeinfo>
#include <iostream>
BOOST_PARAMETER_TEMPLATE_KEYWORD(integral_type)
BOOST_PARAMETER_TEMPLATE_KEYWORD(floating_point_type)
BOOST_PARAMETER_TEMPLATE_KEYWORD(any_type)
using namespace boost::parameter;
using boost::mpl::placeholders::_;
typedef parameters<
  required<tag::integral_type, std::is_integral<_>>,
  required<tag::floating_point_type, std::is_floating_point<_>>,
  required<tag::any_type, std::is_object<_>>
> complicated_signature;
template <class A, class B, class C>
class complicated
{
public:
  typedef typename complicated_signature::bind<A, B, C>::type args;
  typedef typename value_type<args, tag::integral_type>::type integral_type;
  typedef typename value_type<args, tag::floating_point_type>::type
    floating_point_type;
  typedef typename value_type<args, tag::any_type>::type any_type;
};
int main()
{
  typedef complicated<floating_point_type<double>, integral_type<int>,
    any_type<bool>> c;
  std::cout << typeid(c::integral_type).name() << 'n';
  std::cout << typeid(c::floating_point_type).name() << 'n';
  std::cout << typeid(c::any_type).name() << 'n';
}

Example53.3

範例 53.3 使用 Boost.Parameter 將模板引數作為鍵/值對傳遞。與函數一樣,可以按任何順序傳遞模板引數。

該範例定義了一個類 complicated,它需要三個模板引數。因為引數的順序無關緊要,所以它們稱為 A、B 和 C。A、B 和 C 不是存取類別範本時將使用的引數名稱。與函數一樣,引數名稱是使用宏定義的。對於模板引數,使用 BOOST_PARAMETER_TEMPLATE_KEYWORD。範例 53.3 定義了三個引數名稱 integral_type、floating_point_type 和 any_type。

定義引數名稱後,您必須指定可以傳遞的型別。例如,引數 integral_type 可用於傳遞 int 或 long 等型別,但不能傳遞 std::string 等型別。 boost::parameter::parameters 用於建立參照引數名稱的簽名,並定義可以與每個引數一起傳遞的型別。

boost::parameter::parameters 是一個描述引數的元組。必需引數標有 boost::parameter::required。

boost::parameter::required 需要兩個引數。第一個是使用 BOOST_PARAMETER_TEMPLATE_KEYWORD 定義的引數名稱。第二個標識引數可能設定的型別。例如,integral_type 可以設定為整數型別。此要求用 std::is_integral<_> 表示。 std::is_integral<_> 是一個基於 Boost.MPL 的 lambda 函數。 boost::mpl::placeholders::_ 是這個庫提供的預留位置。如果將設定了 integral_type 的型別傳遞給 std::is_integral 而不是 boost::mpl::placeholders::_,並且結果為真,則使用有效型別。其他引數 floating_point_type 和 any_type 的要求以類似方式定義。

建立簽名並將其定義為 complicated_signature 後,複雜類將使用它。首先,使用 complicated_signature::bind 將簽名繫結到模板引數 A、B 和 C。新型別 args 表示傳遞的模板引數與模板引數必須滿足的要求之間的聯絡。接下來,存取 args 以獲取引數值。這是通過 boost::parameter::value_type 完成的。 boost::parameter::value_type 期望引數和要傳遞的引數。該引數確定建立的型別。在範例 53.3 中,類 complicated 中的型別定義 integral_type 用於獲取通過引數 integral_type 傳遞給 complicated 的型別。

main() 存取複雜的範例化類。引數 integral_type 設定為 int,floating_point_type 設定為 double,any_type 設定為 bool。傳遞的引數的順序無關緊要。然後通過 typeid 存取型別定義 integral_type、floating_point_type 和 any_type 以獲取它們的基礎型別。該範例使用 Visual C++ 2013 編譯,將 int、double 和 bool 寫入標準輸出。

範例 53.4。可選模板引數

#include <boost/parameter.hpp>
#include <boost/mpl/placeholders.hpp>
#include <type_traits>
#include <typeinfo>
#include <iostream>
BOOST_PARAMETER_TEMPLATE_KEYWORD(integral_type)
BOOST_PARAMETER_TEMPLATE_KEYWORD(floating_point_type)
BOOST_PARAMETER_TEMPLATE_KEYWORD(any_type)
using namespace boost::parameter;
using boost::mpl::placeholders::_;
typedef parameters<
  required<tag::integral_type, std::is_integral<_>>,
  optional<tag::floating_point_type, std::is_floating_point<_>>,
  optional<tag::any_type, std::is_object<_>>
> complicated_signature;
template <class A, class B = void_, class C = void_>
class complicated
{
public:
  typedef typename complicated_signature::bind<A, B, C>::type args;
  typedef typename value_type<args, tag::integral_type>::type integral_type;
  typedef typename value_type<args, tag::floating_point_type, float>::type
    floating_point_type;
  typedef typename value_type<args, tag::any_type, bool>::type any_type;
};
int main()
{
  typedef complicated<floating_point_type<double>, integral_type<short>> c;
  std::cout << typeid(c::integral_type).name() << 'n';
  std::cout << typeid(c::floating_point_type).name() << 'n';
  std::cout << typeid(c::any_type).name() << 'n';
}

範例 53.4 介紹了可選的模板引數。簽名使用 boost::parameter::optional 作為可選的模板引數。 complicated 中的可選模板引數設定為 boost::parameter::void_,並且 boost::parameter::value_type 被賦予預設值。此預設值是可選引數將設定為的型別,如果型別未另外設定的話。

complicated 在 main() 中範例化。這次只使用引數 integral_type 和 floating_point_type。 any_type 未使用。該範例使用 Visual C++ 2013 編譯,將 integral_type 的 short、floating_point_type 的 double 和 any_type 的 bool 寫入標準輸出。

Boost.Parameter 可以自動檢測模板引數。您可以建立允許將型別自動分配給引數的簽名。與函數引數一樣,需要對模板超程式設計有更深入的瞭解才能做到這一點。

到此這篇關於C++ Boost Parameter超詳細講解的文章就介紹到這了,更多相關C++ Boost Parameter內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com