#Problems compiling code with clang, previously compiled fine with MSVC

26 messages · Page 1 of 1 (latest)

light hill
#

I have been developing a game with SDL targeting Android, but up until today I've only compiled it for desktop with MSVC. SDL has pre-setup shell script that builds the project using Clang. Obviously I didn't expect a flawless transition, and was willing to rewrite the code I needed (which I did a lot). However, several "issues", pointed out by Clang compiler, seem to be incredibly nonsensical. They are:

ocean duneBOT
#

When your question is answered use !solved or the button below to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

light hill
#
  1. Macro param concatenation apparently producing "invalid preprocessing token"
C/C++: E:/Applications/source/repos/InciterGame/src/character/states/goon/goon_idle.cpp:67:1: error: pasting formed 'GoonIdle*', an invalid preprocessing token
C/C++:    67 | GENERIC_STATE_FACTORY_IMPL(GoonIdle);
C/C++:       | ^
C/C++: E:/Applications/source/repos/InciterGame/include/character/states/state.hpp:29:28: note: expanded from macro 'GENERIC_STATE_FACTORY_IMPL'
C/C++:    29 |         reinterpret_cast<StateType##*>(mem_handle)->Init();\
C/C++:       |                                   ^

Macro in question is a boilerplate for a factory class (I could probably convert it to templatized class, but oh well)

#define GENERIC_STATE_FACTORY_IMPL(StateType)                                        \
const StateType##StateFactory* StateType##StateFactory::Instance()                    \
{                                                                                    \
    static const StateType##StateFactory inst;                                        \
    return &inst;                                                                    \
}                                                                                    \
                                                                                    \
void StateType##StateFactory::Create(void* mem_handle, Character& char_for) const    \
{                                                                                    \
    StateType state_inst;                                                            \
    SDL_memcpy(mem_handle, &state_inst, sizeof(StateType));                            \
                                                                                    \
    reinterpret_cast<StateType##*>(mem_handle)->Init();                                \
}```
solar badger
#

In general MSVC is the least conforming of the 3 big compilers, so those are likely MSVC issues, not Clang issues. In particular MSVC defaults to the old buggy preprocessor (the new one can be enabled with /Zc:preprocessor), so any time the old MSVC preprocessor doesn't agree with that of other compilers, it's usually a MSVC bug

#

Right here you can just remove ##, StateType * should work

light hill
#
  1. Complaining about regular variable declarations
C/C++: E:/Applications/source/repos/InciterGame/include/assets/base_asset_bundle.hpp:36:41: error: expected ';' after expression
C/C++:    36 |                 IAssetLifetimeInfo<AssetType>::Deleter deleter{ lt };
C/C++:       |                                                       ^
C/C++:       |                                                       ;
C/C++: E:/Applications/source/repos/InciterGame/include/assets/base_asset_bundle.hpp:36:42: error: use of undeclared identifier 'deleter'
C/C++:    36 |                 IAssetLifetimeInfo<AssetType>::Deleter deleter{ lt };
C/C++:       |```

in a method
```cpp
static void ResourceLoadedInMemory(const void* mem, size_t mem_size, void* userdata)
    {
        auto slot_info = reinterpret_cast<SlotInfo*>(userdata);
        ABaseAssetBundle* bundle = slot_info->Of;

        const IAssetLifetimeInfo<AssetType>* lt = bundle->Lifetime;
        AssetType* loaded_asset = lt->Create(mem, mem_size);

        bundle->LockMutexForAssetInSlot(slot_info->SlotNum);
        IAssetLifetimeInfo<AssetType>::Deleter deleter{ lt };
        bundle->SetAssetInSlot(slot_info->SlotNum, std::shared_ptr<AssetType>{
            loaded_asset, std::move(deleter)
        });
        bundle->UnlockMutexForAssetInSlot(slot_info->SlotNum);
    }```

Where `Deleter` is defined in
```cpp
template<typename AssetType>
class IAssetLifetimeInfo
{
public:
    virtual AssetType* Create(const void* mem, size_t mem_size) const = 0;
    virtual void Destroy(AssetType* asset) const = 0;

    class Deleter
    {
        const IAssetLifetimeInfo* Lifetime;
    public:
        Deleter(const IAssetLifetimeInfo* lt) : Lifetime(lt) {};

        void operator()(AssetType* mem)
        {
            Lifetime->Destroy(mem);
        }
    };
};
solar badger
#

typename IAssetLifetimeInfo<AssetType>::Deleter probably

light hill
#

It does make sense but I didn't know you need that for types that aren't confined to template specialization

ocean duneBOT
#

@light hill Has your question been resolved? If so, type !solved :)

light hill
#

!solved

ocean duneBOT
#

Thank you and let us know if you have any more questions!

This thread is now set to auto-hide after an hour of inactivity

hoary bronze
#

the only way adding a typename would solve a compile error there, is if IAssertLifetimeInfo<AssetType>::Deleter depends on a template parameter in some way

#

in your case I assume AssetType is a template argument of an enclosing template class

#

or ResourceLoadedInMemory is itself a template

light hill
#
template<typename AssetType, typename ResInfoIterType>
class ABaseAssetBundle : public IAssetBundle<AssetType>
{
public:
    struct SlotInfo
    {
        ABaseAssetBundle* Of;
        size_t SlotNum;
    };

private:
    const IAssetLifetimeInfo<AssetType>* Lifetime;
    bool IsLoading = false;

protected:
    virtual void LockMutexForAssetInSlot(size_t slot_num) {};
    virtual void UnlockMutexForAssetInSlot(size_t slot_num) {};

    virtual void SetAssetInSlot(size_t slot_num, std::shared_ptr<AssetType>&& new_asset) = 0;

    static void ResourceLoadedInMemory(const void* mem, size_t mem_size, void* userdata)```
solar badger
hoary bronze
#

then if AssetType comes from the template type, the whole IAssertLifetimeInfo<AssetType>::Deleter depends on the template parameter AssetType and as per language rules you need to disambiguate that "...::Deleter" is a type

#

by adding typename

light hill
hoary bronze
#

and msvc is kinda well known for not enforcing that rule

light hill
#

Yeah, I it was obvious MSVC was very lenient in a lot of stuff