35

虽然我很怀疑,但我很好奇是否可以从现有类型中提取原始类型模板参数,也许使用 RTTI。

例如:

typedef std::bitset<16> WordSet;

是否可以在上面的代码中提取数字 16 而无需在其他地方进行硬编码?欢迎使用编译器特定的实现,尽管我对g++.

4

5 回答 5

51

通常不可能选择任意模板参数。

但是,通常的做法是:

template<int N>
struct foo {
    static const int value = N;
};

对于类型

template<typename T>
struct foo {
    typedef T type;
};

您可以使用foo<39>::value或访问它foo<int>::type

如果您有特定类型,则可以使用部分模板特化:

template<typename>
struct steal_it;

template<std::size_t N>
struct steal_it< std::bitset<N> > {
    static const std::size_t value = N;
};

事实上,同样的原则也适用于类型参数。现在您可以将任何位集传递给它,例如steal_it< std::bitset<16> >::value(注意使用 size_t,而不是 int!)。因为我们还没有可变参数的许多模板参数,所以我们必须将自己限制在特定的参数计数,并重复从 1 到 N 计数的steal_it 模板特化。另一个困难是扫描具有混合参数的类型(类型和非类型参数)。这可能很难解决。

如果你没有类型,而只有一个对象,你可以使用一个技巧,在编译时仍然得到一个值:

template<typename T>
char (& getN(T const &) )[steal_it<T>::value];  

int main() {
    std::bitset<16> b;
    sizeof getN(b); // assuming you don't know the type, you can use the object
}

诀窍是让函数模板自动推断类型,然后返回对字符数组的引用。该函数不需要定义,唯一需要的是它的类型。

于 2008-11-19T07:53:58.087 回答
9

您可以在 C++11 中使用参数推导和未评估的上下文轻松地做到这一点(请注意,为了方便,演示使用 C++14 的变量模板功能)。

#include <type_traits>
#include <iostream>

template<int>
struct foo {};

template<int arg_N>
struct val {
    static constexpr auto N = arg_N;
};

template<template <int> typename T, int N>
constexpr auto extract(const T<N>&) -> val<N>;

template<typename T>
constexpr auto extract_N = decltype(extract(std::declval<T>()))::N;


int main() {
    std::cout << extract_N<foo<5>>;
}

Live demo

于 2018-01-11T08:19:59.053 回答
6

我喜欢 Marc Garcia 的回答,因为它展示了如何以通用方式提取模板参数,但我相信他的示例可以更简单:

#include <type_traits>
#include <iostream>

template<int>
struct MyType {};

template<template <int> typename T, int N>
constexpr int extract(const T<N>&) { return N; }

int main() {
    constexpr MyType<5> myObj;
    std::cout << extract(myObj);
}

Live demo

于 2019-09-29T17:50:20.973 回答
1

在 的情况下std::bitset,您可以只使用size()成员函数:

size_t sz = oh_my_word.size();  // sz is now 16

在一般情况下,您可以定义一个以类似方式返回大小的成员函数:

template <int N>
class Foo
{
public:
  int size() const { return N; }
};
于 2008-11-19T07:20:27.670 回答
1

正如其他答案所述,因为std::bitset您可以通过使用size()成员函数来获取大小,这应该是正确的选择,比任何其他技巧都要好。

有几个针对通用案例的建议,与我在下面建议的几乎相似,但我仍然认为这个更简单:

template <template<std::size_t> typename T, std::size_t K>
auto extractSize(const T<K>&) {
    return K;
}

int main() {
    std::bitset<6> f1;
    std::bitset<13> f2;
    std::cout << extractSize(f1) << std::endl;
    std::cout << extractSize(f2) << std::endl;
}
于 2018-02-04T13:42:26.563 回答