Член функции-аксессора для вариативной шаблонной структуры

В качестве упражнения я разрабатываю ориентированный на цель планировщик действий в Unreal Engine 4. Я пытаюсь настроить свои собственные структуры, которые я могу использовать для динамического описания состояния мира, используя список данных переменной длины, состоящий из отдельных типов переменных. Я думал, что вариативные шаблонные структуры могут быть интересным способом сделать это, но при реализации метода доступа к значению я столкнулся с проблемами.

Я хочу, чтобы он работал, чтобы я мог создавать экземпляры этих структур во время выполнения, используя FDataKeys<T> в общих параметрах для FFact<T...>. Затем я хочу иметь функцию GetValue<S>(string Key), которая будет рекурсивно проверять ключи данных, пока не будет найдено совпадение. Я буду реализовывать параметр флага, чтобы указать на успех или неудачу поиска, но я получаю ошибку компиляции в моем рабочем коде, которая не имеет для меня смысла.

Я знаю, что могу настроить вспомогательный класс со статической функцией для этого, но мне любопытно, почему это не работает и как я смогу реализовать это таким образом, если это возможно.

Сообщение об ошибке:

38:42: предупреждение: ISO C ++ запрещает использование ‘auto’ в объявлении параметра [-Wpedantic] При создании экземпляра ‘S FFact ‹T, R …› :: GetValue (const string &) [with S = char; Т = std :: basic_string; R = {}; std :: string = std :: basic_string] ‘:

50:45: требуется рекурсивно из ‘S FFact ‹T, R …› :: GetValue (const string &) [with S = char; Т = логический; R = {std :: basic_string ‹char, std :: char_traits, std :: allocator›}; std :: string = std :: basic_string] ‘

50:45: требуется от ‘S FFact ‹T, R …› :: GetValue (const string &) [with S = char; T = char; R = {bool, std :: basic_string ‹char, std :: char_traits, std :: allocator›}; std :: string = std :: basic_string] ‘

67:37: требуется отсюда

46:25: ошибка: невозможно преобразовать ‘std :: basic_string’ в ‘char’ в возвращении В функции-члене ‘S FFact ‹T, R …› :: GetValue (const string &) [with S = char; Т = std :: basic_string; R = {}; std :: string = std :: basic_string] ‘:

52: 5: предупреждение: элемент управления достигает конца непустой функции [-Wreturn-type]

Код:

// FFact struct experiments
#include <iostream>
#include <string>
#include <vector>
using namespace std;

// Key-Value data struct
template<typename T>
struct FDataKey
{
    FDataKey(string KeyStr, T Data)
    {
        Key = KeyStr;
        Value = Data;
    }
    
    string Key;
    T Value;
};

// Basic struct to enable generic recursion
template<typename ... T>
struct FFact
{
    // GetValue's bottom of the barrel
    // ToDo: Implement check that Key was not found
    template<typename S>
    S GetValue(string Key)
    {
        S defaultValue;
        return defaultValue;
    }
};

// Variadic templated container meant for FDataKey<> types only
template<typename T, typename ... R>
struct FFact<T, R...>
{
    // Constructors
    FFact(){}
    FFact(const FDataKey<T>& FirstValue, const auto& ...Rest) : Data(FirstValue), Remainder(Rest...)
    {}
    
    // Recursively check Data members for FDataKeys with matching keys
    template<typename S>
    S GetValue(const string& Key)
    {
        if(Data.Key == Key)
        {
            return Data.Value;
        }
        else
        {
            return Remainder.GetValue<S>(Key);
        }
    }
    
    // Member variables
    FDataKey<T> Data;
    FFact<R...> Remainder; 
};

// Run tests
int main() 
{
  // Setup testing Fact
  FFact<char, bool, string> f = FFact<char,bool,string>(
      FDataKey<char>("Initial", 'w'),
      FDataKey<bool>("Cake",false),
      FDataKey<string>("Marco","Polo")
  );
  
  cout << f.GetValue<char>("Initial") << endl;
  cout << f.GetValue<bool>("Cake") << endl;
  cout << f.GetValue<string>("Marco") << endl;
}

return Data.Value; — вы делаете return Data.Value; из каждого рекурсивного вызова, даже когда вы возвращаете S. Бывший. в GetValue<char>. C ++ статически типизирован, тогда каждый Data.Value должен быть преобразован в char.   —  person LazarusOfSuburbia    schedule 21.02.2021

См. также:  Yii создает ошибку приложения на Ubuntu 13.04

Думаю, вот что меня смущает. Поскольку Data.Value не следует возвращать до тех пор, пока ключ не совпадет. Таким образом, единственным преобразованием типа должно быть преобразование S в typeof(Data.Value), которое должно выдавать ошибку только тогда, когда в вызове передаются неправильные универсальные типы.   —  person LazarusOfSuburbia    schedule 21.02.2021

should not be returned он не будет возвращен, но статически все пути должны быть действительными. Как int func() { if (0) { return std::string{}; } return 5; } не будет компилироваться, независимо от того, что строка никогда не возвращается.   —  person LazarusOfSuburbia    schedule 21.02.2021

Понравилась статья? Поделиться с друзьями:
IT Шеф
Комментарии: 1
  1. LazarusOfSuburbia

    Вот и все, он компилируется:

    // FFact struct experiments
    #include <iostream>
    #include <string>
    #include <vector>
    #include <stdexcept>
    #include <type_traits>
    using namespace std;
    
    // Key-Value data struct
    template<typename T>
    struct FDataKey {
        FDataKey(string KeyStr, T Data) {
            Key = KeyStr;
            Value = Data;
        }    
        string Key;
        T Value;
    };
    
    // Basic struct to enable generic recursion
    template<typename ... T>
    struct FFact {
        FFact(){}
        // GetValue's bottom of the barrel
        // ToDo: Implement check that Key was not found
        template<typename S>
        S GetValue(string Key) {
            throw std::runtime_error("key not found");
            S defaultValue;
            return defaultValue;
        }
    };
    
    // Variadic templated container meant for FDataKey<> types only
    template<typename T, typename ...R>
    struct FFact<T, R...> {
        FFact(){}
        // No need to use auto...
        FFact(const FDataKey<T>& FirstValue, const FDataKey<R>&... Rest) : 
        Data(FirstValue), Remainder(Rest...)
        {}
        
        template<typename S>
        S GetValue(const string& Key) {
            if (Data.Key == Key) {
                // you have to statically check 
                // if Data.Value can be converted to S
                // if it can't, then... it can't.
                if constexpr (std::is_convertible<T, S>::value) {
                    return Data.Value;
                } else {
                    throw std::runtime_error("T is not convertiable to S");
                }
            } else {
                // This is the first time I used this syntax, didn't knew about it.
                return Remainder.template GetValue<S>(Key);
            }
        }
        // Member variables
        FDataKey<T> Data;
        FFact<R...> Remainder; 
    };
    
    // Run tests
    int main() 
    {
      // Setup testing Fact
      FFact<char, bool, string> f = FFact<char,bool,string>(
          FDataKey<char>("Initial", 'w'),
          FDataKey<bool>("Cake",false),
          FDataKey<string>("Marco","Polo")
      );
      
      cout << f.GetValue<char>("Initial") << endl;
      cout << f.GetValue<bool>("Cake") << endl;
      cout << f.GetValue<string>("Marco") << endl;
    }
    
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: