masalah dengan spesialisasi parameter templat templat

Saya sering menggunakan konstruksi berikut untuk mengubah argumen run-time (dinamis) menjadi argumen waktu kompilasi (statis).

namespace Foo {
  enum struct option { A,B,C,D,E,F };

  template<template<option> class Func, typename... Args>
  auto Switch(option opt, Args&&...args)
  -> decltype(Func<option::A>::act(std::forward<Args>(args)...))
  {
    switch(opt) {
    case option::A : return Func<option::A>::act(std::forward<Args>(args)...);
    case option::B : return Func<option::B>::act(std::forward<Args>(args)...);
    // etc.
  }
}

Misalnya

template<Foo::option>
void compile_time(std::string const&);         // given

namespace {
  template<Foo::option Opt>
  struct Helper {
    static void act(std::string const&str) { compile_time<Opt>(str); }
  };
}

void run_time_arg(Foo::option opt, std::string const&str)
{
  Switch<CompileTimeArg>(opt,str);
}

Sejauh ini bagus. Tapi sekarang saya punya argumen template lain dan ingin juga blah() memiliki argumen template yang sama. Artinya, secara konseptual saya ingin

template<int, Foo::option>
void compile_time(std::string const&);         // given

namespace {
  template<int Bar, Foo::option Opt>
  struct Helper {
    static void act(std::string const&str) { compile_time<Bar,Opt>(str); }
  };
}

template<int Bar>
void blah(Foo::option opt, std::string const&str)
{
  template<Foo::option Opt> using BarHelper = Helper<Bar,Opt>;
  Switch<BarHelper>(opt, str);
}

tapi, tentu saja, hal itu tidak diperbolehkan (sebuah template dalam lingkup blok dalam fungsi blah()). Jadi, apa solusi yang tepat?

Perhatikan bahwa saya dapat memasukkan semuanya ke dalam templat kelas tambahan

namespace {
  template<int Bar>
  struct Auxiliary
  {
    template<Foo::option Opt> using BarHelper = Helper<Bar,Opt>;
    static void blah(Foo::option opt, std::string const&str)
    { Switch<BarHelper>(opt, str); }
  };
}

template<int Bar>
void blah(Foo::option opt, std::string const&str)
{ Auxiliary<Bar>::blah(opt, str); }

Tapi itu kikuk dan tidak memuaskan. Apakah ada solusi alternatif atau lebih baik? Saya mencoba ini:

template<typename X, typename Y, X x, template<X,Y> class C>
struct specialise {
  template<Y y> using special = C<x,y>;
};

template<int Bar>
void blah(Foo::option opt, std::string const&str)
{
  using Aux = specialise<int, Foo::option, Bar, Helper>
  Switch<Aux::special>(opt, str); }
}

tetapi gcc (5.1.0) mengeluh bahwa S::special diurai sebagai non-tipe sementara instantiasi menghasilkan tipe ... yang salah (menurut saya): instantiasi menghasilkan template (tetap memasukkan typename seperti yang disarankan tidak membantu). Jadi, apa yang salah dan/atau bagaimana cara melakukannya dengan benar/lebih baik?


person Walter    schedule 06.01.2016    source sumber
comment
Tahukah Anda bahwa Anda menggunakan specialize dan specialise? Ini terlihat membingungkan bagi saya.   -  person KompjoeFriek    schedule 06.01.2016
comment
@KompjoeFriek memperbaikinya.   -  person Walter    schedule 06.01.2016
comment
Hanya karena rasa ingin tahu saya ingin tahu apakah ini terkait stackoverflow.com/questions/25202250/ ?   -  person user2672165    schedule 06.01.2016
comment
@ user2672165 dalam beberapa hal ya, tapi tidak secara langsung.   -  person Walter    schedule 07.01.2016


Jawaban (1)


Kata kunci yang akan ditambahkan bukanlah typename karena bukan tipe, melainkan template.

Jadi, panggilan itu seharusnya

template<int Bar>
void blah(Foo::option opt, std::string const& str)
{
    using Aux = specialise<int, Foo::option, Bar, Helper>
    Switch<Aux::template special>(foo, ptr, str);
}

Demo Langsung

person Jarod42    schedule 06.01.2016
comment
benar. Saya telah menemukan jawabannya sendiri sementara ... dan terima kasih atas pengeditannya -- Anda jelas mencobanya! Saya hanya pernah melihat penggunaan kata kunci template ini jika diikuti oleh <>, mis. ptr->template func<0>(). - person Walter; 07.01.2016