对可变参数模板参数的元迭代

use*_*643 15 c++ templates variadic-templates c++11

我想概括以下模式:

template<class A1, class A2, class A3>
class Foo {
protected:
  template<class T>
  void foo(const T& t) {...do stuff...}
public:
  void bar(const A1& a) { foo(a); }
  void bar(const A2& a) { foo(a); }
  void bar(const A3& a) { foo(a); }
};
Run Code Online (Sandbox Code Playgroud)

上述方法不会随着一些不断增加的论点而扩展.所以,我想做:

template<class As...>
class Foo {
protected:
  template<class T>
  void foo(const t& a) {...do stuff...}
public:
  for each type A in As declare:
  void bar(const A& a) { foo(a); }
};
Run Code Online (Sandbox Code Playgroud)

有办法吗?

Nim*_*Nim 12

另一种方法可能是检查bar以确定类型是否在序列中,否则barf带有有用的错误消息,这样可以避免任何继承技巧.

#include <iostream>

struct E {};
struct F {};

template <class... As>
class Foo
{
    template <typename U>
    static constexpr bool contains() {
        return false;
    }

    template <typename U, typename B, typename ...S>
    static constexpr bool contains() {
        return (std::is_same<U, B>::value)? true : contains<U, S...>();
    }

protected:
    template <class T>
    void foo(const T& a) { std::cout << __PRETTY_FUNCTION__ << std::endl; }

public:
    template <class T>
    void bar(const T& a) {
        static_assert(contains<T, As...>(), "Type does not exist");
        foo(a);
    }
};

int main()
{
    Foo<E, F, E, F> f;
    f.bar(F{});
    f.bar(E{});
    f.bar(1); // will hit static_assert
}
Run Code Online (Sandbox Code Playgroud)


Bar*_*rry 9

如果你实际上并不需要的barS和,而不是只需要限制foo-我们可以使用SFINAE允许它的调用只有一个类型,可转换到一个AS:

template <class... As>
class Foo {
public:
    template <class T,
        class = std::enable_if_t<any<std::is_convertible<T, As>::value...>::value>>
    void foo(T const&) { ... }
};
Run Code Online (Sandbox Code Playgroud)

我们可以anybool_pack诀窍来实现的地方:

template <bool... b> struct bool_pack  { };
template <bool... b>
using any = std::integral_constant<bool,
    !std::is_same<bool_pack<b..., false>, bool_pack<false, b...>>::value>;
Run Code Online (Sandbox Code Playgroud)


Pio*_*cki 6

template <class CRTP, class A, class... As>
struct FooBar
{
    void bar(const A& a)
    {
        static_cast<CRTP*>(this)->foo(a);
    }
};

template <class CRTP, class A, class B, class... As>
struct FooBar<CRTP, A, B, As...> : FooBar<CRTP, B, As...>
{
    using FooBar<CRTP, B, As...>::bar;

    void bar(const A& a)
    {
        static_cast<CRTP*>(this)->foo(a);
    }
};

template <class... As>
class Foo : FooBar<Foo<As...>, As...>
{
    template <class, class, class...>
    friend struct FooBar;

protected:
    template <class T>
    void foo(const T& a) { }

public:
    using FooBar<Foo, As...>::bar;
};
Run Code Online (Sandbox Code Playgroud)

DEMO


Mil*_*nek 5

template <class A, class... As>
class Foo : public Foo<As...>
{
protected:
    using Foo<As...>::foo;
public:
    using Foo<As...>::bar;
    void bar(const A& a) { foo(a); }
};

template <class A>
class Foo<A>
{
protected:
    template <class T>
    void foo(const T& t) {  }
public:
    void bar(const A& a) { foo(a); }
};
Run Code Online (Sandbox Code Playgroud)

Piotr Skotnicki的回答类似,这使用继承来构建一个具有bar所有模板参数重载的类.虽然它有点干净,只有一个类模板加上部分特化.