У меня есть функция шаблона, которая повторяется над пакетом параметров. По существу, он предназначен для отображения something.Get<A,B,C>()
в something.Get<A>().Get<B>().Get<C>()
.Рекурсивная функция шаблона не компилируется с помощью Clang?
Это может быть достигнуто путем делать (полный автономный источник ниже сгиба)
template <typename... Pack> class Struct {
std::tuple<Pack...> mTuple;
template <typename Type> auto &GetRef_internal() {
return std::get<first_true<std::is_same<Type, Pack>::value...>::value>(
mTuple);
}
public:
template <typename Current> Current &GetRef() {
return GetRef_internal<Current>();
}
template <typename Current, typename... Next,
typename std::enable_if<sizeof...(Next) != 0>::type * = nullptr>
auto &GetRef() {
auto current = GetRef_internal<Current>();
return current.GetRef<Next...>();
}
};
, где first_true
возвращает индекс первого элемента, который является истинным.
Это компилируется с g ++, и, похоже, на MSVC тоже используется online compiler. При компиляции с clang ++ я получаю следующую ошибку:
test.cxx:40:31: error: expected '(' for function-style cast or type construction
return current.GetRef<Next...>();
~~~~^
test.cxx:38:9: error: cannot deduce return type 'auto &' for function with no return statements
auto &GetRef() {
^
test.cxx:48:12: note: in instantiation of function template specialization 'Struct<Struct<int, Struct<float, float> >, Struct<char>, int>::GetRef<Struct<int, Struct<float, float> >, Struct<float, float> , nullptr>' requested here
.GetRef<Struct<int, Struct<float, float>>, Struct<float, float>>();
^
2 errors generated.
Что может быть причиной этого?
p.s. Фактический «производственный код» более полезен, чем пример, кажется, но это было бы слишком много для публикации здесь.
================================================================================================================================== ===========================
#include <tuple>
#include <type_traits>
// Template to check if condition holds true for all members of a parameter
// pack.
template <bool... b> struct BoolArray {};
template <bool... b>
using all_true = std::is_same<BoolArray<b...>, BoolArray<(b, true)...>>;
//helper type trait
template <bool... b> struct first_true {
template <
unsigned index = 0,
typename std::enable_if<index<sizeof...(b)-1>::type * =
nullptr> static constexpr unsigned check() {
return std::get<index>(std::make_tuple(b...)) ? index : check<index + 1>();
}
template <unsigned index = 0,
typename std::enable_if<index >= sizeof...(b)-1>::type * = nullptr>
static constexpr unsigned check() {
return std::get<index>(std::make_tuple(b...)) ? index : 0;
}
static constexpr unsigned value = first_true<b...>::check();
};
//The actual problem struct
template <typename... Pack> class Struct {
std::tuple<Pack...> mTuple;
template <typename Type> auto &GetRef_internal() {
return std::get<first_true<std::is_same<Type, Pack>::value...>::value>(
mTuple);
}
public:
template <typename Current> Current &GetRef() {
return GetRef_internal<Current>();
}
template <typename Current, typename... Next,
typename std::enable_if<sizeof...(Next) != 0>::type * = nullptr>
auto &GetRef() {
auto current = GetRef_internal<Current>();
return current.GetRef<Next...>();
}
};
int main() {
// Define a random nested struct
Struct<Struct<int, Struct<float, float>>, Struct<char>, int> myStruct;
// Then retrieve one of the substructures to instantiate the template
auto substruct =
myStruct
.GetRef<Struct<int, Struct<float, float>>, Struct<float, float>>();
return 0;
}
Это сработало! сегодня узнали что-то новое. Примите этот ответ, как только это позволит мне. Интересно, что g ++ разрешает его даже с -pedantic. –
@CodingCat spec говорит, что если у вас есть «foo.bar <», чтобы узнать, является ли «бар» шаблоном, сначала его нужно искать в классе «foo». И если «bar» там не найден, его нужно искать в контексте всего выражения. Но чтобы узнать, присутствует ли он в классе объекта, он должен сначала подождать, пока не будет создан экземпляр окружающего шаблона. По-видимому, Кланг делает это. GCC не делает, поэтому считает, что это шаблон. Это также проблема в https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55576, я думаю. В этом сообщении GCC отвергает действительную программу. –
Вся цель шаблона «шаблон» заключается в том, чтобы помочь компилятору решить, является ли это имя шаблоном. Но GCC решает сделать это самостоятельно, не используя disambiguator, и поэтому находит «GetRef» в контексте выражения в качестве члена. Я не думаю, что это поведение GCC верное. –