Error trying to store a UDataTable in a TMap as value

Hi all!

I have a TMap declared as follow: TMap<FString, UDataTable>* providerCatalogs;
All my code works, but, if i do this: catalogs->Add(providerName, *dataTable);

i get this error:

“Error 1 error C2248: ‘UDataTable::UDataTable’ : no se puede obtener acceso al miembro private miembro declarado en la clase ‘UDataTable’ M:\Epic Games\4.8\Engine\Source\Runtime\Core\Public\Containers\Map.h 59 1 MyShop”

This is my full code:

Providers.h



// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMisc.h"
#include "ProviderCatalog.h"
#include "GameFramework/Actor.h"
#include "Providers.generated.h"



class ProviderCatalogFinder : public IPlatformFile::FDirectoryVisitor
{
    virtual bool Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory);

private:
    TMap<FString, UDataTable>* catalogs;

public:    
    ProviderCatalogFinder(TMap<FString, UDataTable>* providerCatalogs);
};


/**
 * The article providers
 */
UCLASS(Blueprintable, BlueprintType)
class MYSHOP_API AProviders : public AActor
{
	GENERATED_BODY()

private:
    FString PROVIDERS_PATH = "Providers/";
    FString PROVIDERS_LIST = "Providers.txt";

    TMap<FString, UDataTable>* providerCatalogs;
	
public:	
	// Sets default values for this actor's properties
	AProviders();

	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	
	// Called every frame
	virtual void Tick( float DeltaSeconds ) override;

	// Loads the available provider catalogs
    void LoadCatalogs();
};


Providers.cpp



// Fill out your copyright notice in the Description page of Project Settings.

#include "MyShop.h"
#include "Providers.h"



ProviderCatalogFinder::ProviderCatalogFinder(TMap<FString, UDataTable>* providerCatalogs)
{
    catalogs = providerCatalogs;
}


bool ProviderCatalogFinder::Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory)
{
    if (!bIsDirectory)
    {
        FString file = FString(FilenameOrDirectory);

        if (FPaths::GetExtension(file).ToLower() == "csv")
        {
            FString catalogData;
            FString providerName;
            FFileHelper::LoadFileToString(catalogData, *file);
            TArray<FString> errors;

            if (!catalogData.IsEmpty())
            {
                providerName = FPaths::GetCleanFilename(file);

                UE_LOG(LogTemp, Log, TEXT("Processing the catalog of the provider '%s' ..."), *providerName);

                UDataTable* dataTable = NewObject<UDataTable>(UDataTable::StaticClass());

                dataTable->RowStruct = FProviderCatalog().StaticStruct();
                errors = dataTable->CreateTableFromCSVString(catalogData);

                if (errors.Num() > 0)
                {
                    UE_LOG(LogTemp, Error, TEXT("There were errors processing the catalog:"));

                    for (FString error : errors)
                    {
                        UE_LOG(LogTemp, Error, TEXT("- %s"), *error);
                    }

                    UE_LOG(LogTemp, Error, TEXT("-----------------------------------------"));
                }
                else
                {                    
                    UE_LOG(LogTemp, Log, TEXT("Found %i articles in the catalog."), dataTable->GetRowNames().Num());
                    catalogs->Add(providerName, *dataTable);
                }

                return true;
            }            
        }
    }

    return false;
}


// Sets default values
AProviders::AProviders()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}


// Called when the game starts or when spawned
void AProviders::BeginPlay()
{
	Super::BeginPlay();
    
    providerCatalogs = new TMap<FString, UDataTable>();

    LoadCatalogs();
}


// Called every frame
void AProviders::Tick( float DeltaTime )
{
	Super::Tick( DeltaTime );

}


void AProviders::LoadCatalogs()
{
    FString catalogsDir = (FPaths::GameContentDir() + PROVIDERS_PATH);
    ProviderCatalogFinder catalogFinder = ProviderCatalogFinder(providerCatalogs);

    UE_LOG(LogTemp, Log, TEXT("Loading available provider catalogs from '%s' ..."), *catalogsDir);
    
    FPlatformFileManager::Get().GetPlatformFile().IterateDirectory(*catalogsDir, catalogFinder);

    UE_LOG(LogTemp, Log, TEXT("Loaded %i catalogs."), providerCatalogs->Num());
}


Thanks for your assistance :slight_smile: .

See ya!

You cannot store any UObject in a TMap by value, just as you cannot construct a UObject directly on the stack. You need to change your map definition to:


 TMap< FString, UDataTable* > 

and modify your code accordingly.

Great, all works now, thanks! :smiley:

See ya!

P.D: Errr… i think i hit another problem with pointers :S.
I changed my TMap this way:



class ProviderCatalogs : public TMap < FString, UDataTable* > {};

...]

ProviderCatalogs* catalogs;


I’m using pointers because i need that this “catalogs” variable be modified by my DirectoryVisitor class.

All was working fine, until i tried this:



UDataTable* providerArticles = catalogs[provider];


and i got this error:

Error 1 error C2677: ‘’ binario : no se encontró un operador global que adopte el tipo ‘FString’ (o bien no existe una conversión aceptable) M:\Documentos\Copy\Programacion\Proyectos\UE4\MyShop\Source\MyShop\Providers.cpp 119 1 MyShop

I don’t know what i’m doing wrong. I created a pointer to a ProviderCatalogs object, that is really a TMap<FString, UDataTable*>, so, i should be able to access a value with a string key, right? :frowning: .

See ya!

P.D 2: I forgot to specify that “provider” is a FString, this is the function at the moment:



void AProviders::GetArticle(FString provider, FString articleCode)
{
    if (catalogs->Num() > 0)
    {
        if (catalogs->Contains(provider))
        {
            **UDataTable* providerArticles = catalogs[provider];**
            
            //providerArticles->FindRow(articleCode, TEXT("Searching article"));
        }
    }
}


catalogs is a pointer. You should only have to dereference it first, then you can use its ] operation.


(*catalogs)[provider];

Oh my… i need to revise all about pointers, too much years without using C++ i think >_< .

Thanks a lot for the help :).

See ya!