C++ inicializácia immutable typov

C++ inicializácia immutable typov
« kdy: 09. 12. 2020, 01:04:55 »
Na úvod len spomeniem že používam najnovšiu verziu C++ kompilátr čisatočne podporuje C++ 20, ktorá ešte tuším ani neni hotová, ale niektoré časti normy sú už známe a všetky najrzšírenejšie C++ kompilátory ju do určitej miery podporujú... To čo tu rozoberám je súčasťou C++ 20... a teraz k veci.

Mám takýto typ:

Kód: [Vybrat]
struct FileTimesInfo
{
const __time64_t LastAccessTime;
const __time64_t LastModificationTime;
const __time64_t LastStatusChangeTime;
};

ktorý vieme inicializovať takto (namiesto núl si tam doplnte hodnoty aké chcete):

Kód: [Vybrat]
auto ti = FileTimesInfo{ .LastAccessTime = 0, .LastModificationTime = 0, .LastStatusChangeTime = 0 };
keď ale typu pridám nejaký konštruktor napr.

Kód: [Vybrat]
struct FileTimesInfo
{
const __time64_t LastAccessTime;
const __time64_t LastModificationTime;
const __time64_t LastStatusChangeTime;

FileTimesInfo(struct _stati64 stat) :
LastAccessTime(stat.st_atime),
LastModificationTime(stat.st_mtime),
LastStatusChangeTime(stat.st_ctime)
{
}
};

Tak sa dá inicializovať len cez ten nadefinovaný konštruktor. Ale už ho neviem inicializovať tak ako pred tým:

auto ti = FileTimesInfo{ .LastAccessTime = 0, .LastModificationTime = 0, .LastStatusChangeTime = 0 };

Prečo to tak je? a ako tento problém napraviť tak aby som mohol inicializovať triedu oboma spôsobmi? Aj cez custom konštruktor aj cez inializátor? Teraz si len domýšlam... moj predpoklad je že keď v C++ nenadefinujem žiadny konštruktor C++ nadefinuje nejaký implicitný defaultný konštruktor, ktorý umožňuje atribúty inicializovať priamo cez inicializátor. keď ale explicitne nadefinujem konštruktor prídem o ten implicitný ktorý C++ vytvára automaticky. Ako teda triede definovať custom konštruktor pričom nechcem prísť aj o tú formu priamej inicuializácie cez membery? Vopred ďakujem za vysvetlenie.


Re:C++ inicializácia immutable typov
« Odpověď #1 kdy: 09. 12. 2020, 02:50:21 »
Bohužel nelze kombinovat uživatelský konstruktor a inicializaci jako v C (aggregate initialization).

https://en.cppreference.com/w/cpp/language/aggregate_initialization
Citace
An aggregate is one of the following types:
class type (typically, struct or union), that has
no user-declared or inherited constructors

Šlo by to obejít vytvořením statické metody místo konstruktoru, např.:
Kód: [Vybrat]
struct FileTimesInfo
{
    const __time64_t LastAccessTime;
    const __time64_t LastModificationTime;
    const __time64_t LastStatusChangeTime;

    constexpr static FileTimesInfo create(const struct _stati64& stat) noexcept
    {
        return FileTimesInfo{
                 .LastAccessTime = stat.st_atime,
                 .LastModificationTime = stat.st_mtime,
                 .LastStatusChangeTime = stat.st_ctime
               };
    }
};
« Poslední změna: 09. 12. 2020, 02:56:06 od Wladows »

mjakl

Re:C++ inicializácia immutable typov
« Odpověď #2 kdy: 09. 12. 2020, 11:16:00 »
Potřebujete constructor, co bere std::initializer_list.

Re:C++ inicializácia immutable typov
« Odpověď #3 kdy: 13. 12. 2020, 22:45:14 »
Bohužel nelze kombinovat uživatelský konstruktor a inicializaci jako v C (aggregate initialization).

https://en.cppreference.com/w/cpp/language/aggregate_initialization
Citace
An aggregate is one of the following types:
class type (typically, struct or union), that has
no user-declared or inherited constructors

Šlo by to obejít vytvořením statické metody místo konstruktoru, např.:
Kód: [Vybrat]
struct FileTimesInfo
{
    const __time64_t LastAccessTime;
    const __time64_t LastModificationTime;
    const __time64_t LastStatusChangeTime;

    constexpr static FileTimesInfo create(const struct _stati64& stat) noexcept
    {
        return FileTimesInfo{
                 .LastAccessTime = stat.st_atime,
                 .LastModificationTime = stat.st_mtime,
                 .LastStatusChangeTime = stat.st_ctime
               };
    }
};

Vďaka za tento hack príznam sa že ma to ani nenapadlo aj keď som to v iných jazykoch občas používal. A ďakujem aj za informáciu, že to nejde, ostáva len dúfať že to zase opravia v > 20 verzii C++. V iných jazykoch sa objekty takto dajú bežne inicializovať a funguje to aj keď majú custom konštruktor, napr. C#:

Kód: [Vybrat]
class SomeComponent
{
    public string Status { get; private set; }
    public bool IsEnabled { get; set; }
    public SomeComponent(string status)
    {
        Status = status;
        IsEnabled = false;
    }

    public void DisplayStatus()
    {
        Console.WriteLine(
            IsEnabled
                ? "Enabled with status: " + Status
                : "Disabled"
        );
    }
}

var abc = new SomeComponent("Abc") { IsEnabled = true };
abc.DisplayStatus();

[quote author=mjakl link=topic=23970.msg341350#msg341350 date=1607508960]
Potřebujete constructor, co bere std::initializer_list.
[/quote]

Initializer list má template parameter a keď chcete inicializovať viac typov tak čo mu predáte? Okrem toho skúšal som to a nepodarilo sa mi to zfunkčniť takým spôsobom ako som načrtol v prvom poste.

mjakl

Re:C++ inicializácia immutable typov
« Odpověď #4 kdy: 14. 12. 2020, 10:47:03 »
Pokud chcete různé typy, tak můžete použít třeba tuple.