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:
#Problems compiling code with clang, previously compiled fine with MSVC
26 messages · Page 1 of 1 (latest)
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.
- 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(); \
}```
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
Thanks, that did seem to work. Unfortunately, that's not all
- 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);
}
};
};
typename IAssetLifetimeInfo<AssetType>::Deleter probably
That's crazy
It does make sense but I didn't know you need that for types that aren't confined to template specialization
@light hill Has your question been resolved? If so, type !solved :)
Yeah, the rest were essentially these 2 problems in a different form. Thanks
!solved
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
ResourceLoadedInMemory is almost certainly inside a template
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
ResourceLoadedInMemory is a static function defined within a templatized class, yes
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)```
What's "confined to template specialization"? 
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
template<bool True?>
class True
{}
template<true>
class True
{
using TrueYes = std::true_type;
}```
and msvc is kinda well known for not enforcing that rule
Yeah, I it was obvious MSVC was very lenient in a lot of stuff