У меня есть сложный сторонний код, использующий шаблоны. С gcc 7.3.0 он строится нормально, если указан флаг gcc -std = gnu ++ 98, но в противном случае выдает ошибку компиляции (то есть при компиляции C++ 11). Мне нужно исправить компиляцию C++ 11. Вот код (извините, он не полный, но файлы заголовков сложны):
#define CPP11 (__cplusplus > 199711L)
namespace csl
{
namespace PostExec
{
struct Complement
{
static int64_t Execute(int64_t v)
{
return ~v;
}
};
template<size_t bitWidth, bool maskOutput>
struct Mask
{
static int64_t Execute(int64_t v)
{
return 0;
}
};
#if CPP11
template<typename P, typename... PS>
struct Compound
{
template<typename T>
static T&& Execute(T&& v)
{
if (sizeof...(PS) > 0)
{
return Compound<PS...>::Execute(P::Execute(std::forward<T>(v))); <<<< COMPILER ERROR HERE
}
return P::Execute(std::forward<T>(v));
}
};
#else
template<typename P1, typename P2>
struct Compound
{
static int64_t Execute(int64_t v)
{
return P1::Execute(P2::Execute(v));
}
};
#endif
}
}
using namespace csl;
class CModel
{
public:
void f1();
private:
void Execute() { }
static const size_t PAGE_COUNT = 1;
static size_t CurrentPage;
static CPage<1, 0> State[PAGE_COUNT];
};
void CModel::f1()
{
int64_t n[5];
StepLogicalNXOr<1, false>::Execute(Page.N[1], n[0], n[1]);
}
size_t CModel::CurrentPage = 0;
CPage <1919, 0> CModel::State[PAGE_COUNT] = {
CPage <1, 0>()
};
Ошибка компилятора (когда определен CPP11):
<snip>: error: wrong number of template arguments (0, should be at least 1)
return Compound<PS...>::Execute(P::Execute(std::forward<T>(v)));
~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<snip>: note: provided for ‘template<class P, class ... PS> struct csl::PostExec::Compound’
struct Compound
^~~~~~~~
Я понимаю, что это сложно, но если кто-нибудь сможет помочь, буду благодарен.





Вы пробовали с SFINAE?
Я имею в виду ... что-то вроде (осторожно: код не проверен)
template<typename T>
static typename std::enable_if<0 != sizeof...(PS), T&&>::type Execute(T&& v)
{ return Compound<PS...>::Execute(P::Execute(std::forward<T>(v))); }
template<typename T>
static typename std::enable_if<0 == sizeof...(PS), T&&>::type Execute(T&& v)
{ return P::Execute(std::forward<T>(v)); }
Я имею в виду ... ваш код не может работать, потому что, когда sizeof...(PS) == 0 строка
return Compound<PS...>::Execute(P::Execute(std::forward<T>(v)));
компилируется, и Compound требует один или более аргументов шаблона; не может принимать нулевой аргумент шаблона.
Я знаю, что эта линия проходит испытания
if (sizeof...(PS) > 0)
а тебе нужен if constexpr
if constexpr (sizeof...(PS) > 0)
чтобы избежать компиляции при ложном тесте; но if constexpr, к сожалению, доступен только начиная с C++ 17.
Итак, единственное решение, которое я вижу в C++ 11, - это разделить метод Execute() на две версии и включить / отключить первую или вторую в соответствии со значением sizeof...(PS).
Ошибка: ошибка: вызов перегруженного 'Execute (int64_t)' неоднозначен iq = PostExec :: Compound <PostExec :: Mask <bitWidth, maskOutput>, PostExec :: Complement> :: Execute (BitwiseOps :: XOr :: Execute (ia, ib)); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~ ^ ~~~~~~~~ ~~~~ ~~~~~~~~~~~~~~~~~~~~ ~
@DavidA - извините: я забыл ::type после std::enable_if<> для второго случая; Я не знаю, проблема ли в этом (я так не думаю, если честно), но мой первый ответ неверен; ответ исправлен. Можете попробовать с исправленным кодом?
Код компилируется с этим изменением. Спасибо. Судя по вашему комментарию к ritesh, вы считаете, что ваше решение более правильное, чем его?
@DavidA - да, потому что опубликованный вами код намеревается (неправильно) рекурсивно вызывать Execute(), используя типы Ps...; в решении ritesh список шаблонов никогда не меняется: всегда есть P, Ps...; поэтому код компилируется, но (если я не ошибаюсь) вызывает сам себя, пока не будет достигнут предел рекурсии.
Спасибо за вашу помощь. Я очень благодарен. Я принял твой ответ.
Compound<PS...>::Execute(P::Execute(std::forward<T>(v)));
P в приведенном выше вызове является причиной проблемы. Составной шаблон принимает 2 аргумента, и здесь передается только 1.
Я пробовал в рамках всех заданных ограничений и считаю, что приведенный ниже код должен предотвратить ошибку компилятора.
template<typename P, typename... PS>
struct Compound
{
template<typename T>
static T&& Execute(T&& v)
{
if (sizeof...(PS) > 0)
{
return Compound<P,PS...>::Execute(P::Execute(std::forward<T>(v)));
}
return P::Execute(std::forward<T>(v));
}
};
Я надеюсь, что это помогает.
предотвратить ошибку компилятора, но не использует список P, Ps...
Привет, Ритеш, спасибо за ваш ответ, но кажется, что ответ max66 более полный, поэтому я принял это.
Спасибо за Ваш ответ. Я попробовал предложенный вами код (ваш первый блок кода), но теперь получаю сообщение об ошибке для строки iq = PostExec :: Compound <PostExec :: Mask <bitWidth, maskOutput>, PostExec :: Complement> :: Execute (BitwiseOps :: XOr :: Выполнить (ia, ib));