带有可变参数模板的标记调度,c ++ 11

时间:2014-07-25 15:33:55

标签: c++ templates c++11 variadic-templates template-function

我正在尝试使函数接受不同的参数,具体取决于枚举。

// cake.h
#pragma once
#include <utility>

enum class TYPE { CupCake, Jelly, BirthdayCake };

struct cake_tin { /* etc etc */ };

/** Fills in different ingredients for different types of cake */
template <TYPE, typename ...Args>
void fill_tin(cake_tin &tin, Args... args);

/** Bakes a cake */
template <TYPE type, typename ...Args>
void bake_cake(Args&&...args) {
    cake_tin tin;
    fill_tin<type>(tin, std::forward<Args>(args)...);
}

.cpp文件包含函数的特化

// cake.cpp
#include "cake.h"

// If I put this in cake.h, I get multiple definition error (since the template's fully specalised), but if I move this to the .cpp file, I get undefined reference when I compile
template <>
void fill_tin<TYPE::CupCake>(cake_tin &tin, int cherries) {
    // ... etc etc
}

template <>
void fill_tin<TYPE::Jelly>(cake_tin &tin, bool wobble) {
    // ... etc etc
}

完整性

// main.cpp
#include "cake.h"

int main() {
    bake_cake<TYPE::CupCake>(1);
}

包含cake.h

的其他文件
// other.cpp
#include "cake.h"

使用clang++ -Wall -Wextra -std=c++11 main.cpp other.cpp -o main

进行编译

我尝试过申报

template <> void fill_tin<TYPE::CupCake>(cake_tin &tin, int cherries);
template <> void fill_tin<TYPE::Jelly>(cake_tin &tin, bool wobble);

仍然无法实例化该模板。如果我将特化项移到标题中,那么当标题包含在链接阶段的多个编译单元中时,它们将导致重新定义。

我的问题是:我怎样才能让它发挥作用,或者有更好的方法来实现这一目标吗?

1 个答案:

答案 0 :(得分:5)

尝试将模板专业化与函数重载混合在一起总是非常痛苦。

提供类模板特化:

template<TYPE> struct tin_filler;  // undefined
template<> struct tin_filler<TYPE::CupCake> {
    void operator()(cake_tin& tin, int cherries); };
template<> struct tin_filler<TYPE::Jelly> {
    void operator()(cake_tin& tin, bool wobble); };

template <TYPE type, typename ...Args>
void bake_cake(Args&&...args) {
    cake_tin tin;
    tin_filler<type>()(tin, std::forward<Args>(args)...);
}

或使用integral_constant来验证TYPE并使用正常函数重载:

void fill_tin(std::integral_constant<TYPE, TYPE::CupCake>, cake_tin& tin, int cherries);
void fill_tin(std::integral_constant<TYPE, TYPE::Jelly>, cake_tin& tin, bool wobble);

template <TYPE type, typename ...Args>
void bake_cake(Args&&...args) {
    cake_tin tin;
    fill_tin(std::integral_constant<TYPE, type>(), tin, std::forward<Args>(args)...);
}

前者更为一般,但在这种情况下,后者可能更清晰,更简单。

相关问题