使用模板模板参数进行模板定义的函数专用化



按照@Jonas在上一个问题中的建议,我定义了一个模板化类来保存任意包含对象(字符串、树等(的任意容器(向量、集合、映射等(。到目前为止,我的定义是这样的:

template <template <typename...> class Container, typename Containee = std::string, typename... extras>
class Lemario
{
public:
typedef typename Container<Containee, extras...>::iterator iterator;
typedef typename Container<Containee, extras...>::const_iterator const_iterator;
// Use 'Containee' here (if needed) like sizeof(Containee)
// or have another member variable like: Containee& my_ref.
Container<Containee, extras ...> mTheContainer;
int loadContainees(const char *filename) {
Containee w, line;
// do some stuff here
}
void appendContainee(const Containee &__x);
};

现在,我可以在内联(如 loadContainees(和模板定义外部定义方法。外面:

template <template <typename...> class Container, typename Containee, typename... extras>
Containee Lemario<Container, Containee, extras...>::transform_word(const     Containee& word) const
{
Containee result;
return result;
}

目前为止,一切都好。

但是现在我想专门使用一种方法将Contaniee作为向量,映射,树附加到容器中,使用不同的方法。所以我尝试专门化 std::vector:

template <template <typename...> class Container, typename Containee, typename... extras>
void Lemario<std::vector, Word>::appendContainee(const Word & word)
{
mTheContainer.push_back(word);
}

但是我收到以下错误:

error: prototype for ‘void Lemario<std::vector, gong::Xtring>::appendContainee(const Word&)’ does not match any in class ‘Lemario<std::vector, gong::Xtring>’

除此之外,我只能专用于容器 std::vector ,但让包含对象不专用吗?

template <template <typename...> class Container, typename Containee, typename... extras>
void Lemario<std::vector, Containee>::appendContainee(const Containee & word)
{
mTheContainer.push_back(word);
}

问题是你的appendContainee实现存在语法错误。将函数专用化为std::vectorWord的正确方法是这样编写:

template <>
void Lemario<std::vector, Word>::appendContainee(const Word & word)
{
mTheContainer.push_back(word);
}

演示


但是,此方法要求您每次都完全专用化函数,这意味着您必须同时指定容器类型。可能您只想专注于std::vector而不是Word

此问题通常使用标记调度模式来解决。在标记调度中,我们通过引入将通过重载正确选择的帮助程序方法,将专用化转变为重载问题。

我们在类中创建一个空的嵌套模板化结构:

private:
template<class...>
struct Lemario_tag{};

然后编写入口点方法将调用private帮助程序方法:

template<class T>
void appendContaineeHelp(const Containee &x, Lemario_tag<T>)
{
static_assert(sizeof(T) == 0, "No specialization exists for this container");
}
void appendContaineeHelp(const Containee &x, Lemario_tag<std::vector<Containee, extras...>>)
{
mTheContainer.push_back(x);
}

第一个是 catch-all,如果您尝试使用非专用容器调用它,则会导致编译器错误。

第二个是专门用于std::vector的。

我们这样定义我们的publicappendContainee(简单的直通(:

void appendContainee(const Containee &x){
appendContaineeHelp(x, Lemario_tag<Container<Containee, extras...>>{});
}

我们可以像这样使用我们的容器:

Lemario<std::vector, std::string> vecString;
Lemario<std::vector, int> vecInt;
vecString.appendContainee("foo");
vecInt.appendContainee(1);
Lemario<std::set, int> set_int;
// set_int.appendContainee(1); // compiler error

更好的演示

您可以使用std::enable_if(和SFINAE(来专门化该功能,这是一个在线示例。

template <template <typename...> class Container, typename Containee = std::string, typename... extras>
class Lemario
{
public:
typedef typename Container<Containee, extras...>::iterator iterator;
typedef typename Container<Containee, extras...>::const_iterator const_iterator;
// Use 'Containee' here (if needed) like sizeof(Containee)
// or have another member variable like: Containee& my_ref.
Container<Containee, extras ...> mTheContainer;
int loadContainees(const char *filename) {
Containee w, line;
// do some stuff here
return 0; // To make the compiler happy
}
template <typename Containee2> // For SFINAE to work
typename std::enable_if<std::is_same<Container<Containee2, extras...>, std::vector<Containee2, extras...>>::value>::type
appendContainee(const Containee2 & word)
{
mTheContainer.push_back(word);
}
template <typename Containee2> // For SFINAE to work
typename std::enable_if<std::is_same<Container<Containee2, extras...>, std::deque<Containee2, extras...>>::value>::type
appendContainee(const Containee2 & word)
{
mTheContainer.push_back(word);
}
};

int main()
{
Lemario<std::vector, int> foo;
std::cout << foo.mTheContainer.size() << std::endl;
foo.appendContainee(1);
std::cout << foo.mTheContainer.size() << std::endl;
Lemario<std::deque, int> bar;
std::cout << bar.mTheContainer.size() << std::endl;
bar.appendContainee(1);
std::cout << bar.mTheContainer.size() << std::endl;
}

最新更新