Juliean

GDNet+ Basic
  • Content count

    1641
  • Joined

  • Last visited

Community Reputation

7084 Excellent

About Juliean

  • Rank
    Contributor

Personal Information

Recent Profile Visitors

26734 profile views
  1. Nested namespaces useless typing?

    Note that in C++17, there is a feature actually called "nested namespaces", which can make such code way easier to read/write: // might be worth a discussion if this is actually better when there are multiple nested namespaces in one file namespace my::paths { const char *ExtractFileName(const char *path); namespace my::strings { size_t GetAnsiStringLength(const char *str); }; // could instead look like this: namespace my { namespace system::io::path { const char *ExtractFileName(const char *path); }; namespace strings { size_t GetAnsiLength(const char *str); }; }; They are also a better alternative for "smurf naming convention". I worked at a project where every class was prefixed with proj_module_nested_ ... you could argue that this is already an iditiotic naming scheme, but in multi-million line projects, its important to be able to quickly see to which module a certain method/class belongs. I'd actually prefer IO::Paths::GetHome() etc... I tend to group my global methods in a static class instead of a namespace, so I'm just used to seeing multiple levels of nested :: without a problem. I also tend to not using namespace, but instead put all implementations in their respective namespace as well: namespace my::strings { const char* something(const char* path) { IO::Paths::GetHomePath(); // my is implicitely available, as well as my::strings. } } But thats just my sense, in case you want to get some different ideas.
  2. __declspec(selectany)

    Appearently it ensures COMDAT-folding: https://msdn.microsoft.com/en-us/library/5tkz6s71.aspx
  3. Ah, I didn't even notice the alloca. This perfectly explains whats happening here, and I'm even wondering that the compiler isn't optimizing it more aggressively than it already is. Lets recap what you are telling the compiler here: 1: You want some memory off the stack. Unlike _malloca or equivalents, alloca will always be stack based, so the compiler can be sure about that. 2: You are returning a pointer to this memory, which is only valid inside this function. So that tells the compiler that the return-statement, while being able to return the current pointer of the allocation as-is would be valid, the caller of the function would then point to invalid memory, so this should be undefined behaviour. 3: Furthermore, you are not using the destBuffer outside of strncpy-ing to it in the end. Since the compiler can assume that the value of destBuffer is not going to be used after strncpy for return being undefined behaviour, I belive it can optimize it away (at least thats the case for memcpy, so don't hang me if I'm wrong about that). 4. So that means that the compiler is left with an allocation that is literally unused, which means it can probably just remove it (though from what you describe thats not happening, so maybe it is pretenting to allocate, but just generates the address that the allocation would be at, so that i can return *something* at the end?) So maybe thats whats already happening (hard to tell w/o the assembly), but a compiler could just turn that whole code into: If(destBuf != nullptr) // execute function code; return destBuf; else // do nothing return WHATEVER_VALUE. // probably eigther garbage or a pointer along the stack where the allocation would start I'm no expert on compilers but I'm pretty sure thats exactly whats happening. The compiler usually is not allowed to alter the visible behaviour of the program, unless you are, as in your case, relying on undefined behaviour - so the lesson is, never invoke undefined behaviour
  4. In your original code, "destLen" isn't used outside of assignment and the assert though, so the compiler will totally optimize that away. It should still enter the branch and assign the destBuffer though, are you sure that didn't happen as well?
  5. The closest I found was "EditCondition", which allows you to control whether a property can be edited, but requires a separate boolean UPROPERTY: https://wiki.unrealengine.com/UPROPERTY#EditCondition You might want to check the whole list on that wiki-page though, maybe I overlooked something - if what you want exist, it should show up there.
  6. Ah, thats much nicer than my solution, even after I simplified it a bit I'll just have to modify it a bit, as I also need to collapse all tuples recursively - so std::tuple<int, std::tuple<bool, void>, float> becomes std::tuple<int, bool, float>. Thats currently done by this monstrosity: namespace impl { template<typename... Args> struct MergeTuple { }; template<typename... Args, typename... Args2> struct MergeTuple<std::tuple<Args...>, std::tuple<Args2...>> { using type = std::tuple<Args..., Args2...>; }; template<typename... Args> using MergeTupleType = typename MergeTuple<Args...>::type; template<typename... Args> struct ConcatTupleHelper { using type = std::tuple<Args...>; }; template<typename... Types> using ConcatTupleTypes = typename ConcatTupleHelper<Types...>::type; template<typename Arg> struct ConcatTupleHelper<Arg> { using type = std::tuple<Arg>; }; template<typename... Args> struct ConcatTupleHelper<std::tuple<Args...>> { using type = ConcatTupleTypes<Args...>; }; template<typename... Args, typename... Args2> struct ConcatTupleHelper<std::tuple<Args...>, std::tuple<Args2...>> { using type = ConcatTupleTypes<Args..., Args2...>; }; template<typename Arg, typename Arg2, typename... Args> struct ConcatTupleHelper<Arg, Arg2, Args...> { using type = MergeTupleType<ConcatTupleTypes<Arg>, ConcatTupleTypes<Arg2, Args...>>; }; } template<typename... Types> using ConcatTupleTypes = impl::ConcatTupleTypes<Types...>; But I'm sure it will be easier with your code
  7. Uh, nevermind, found a solution (at least for removing the void from tuple): // concat-tuple => constructs one tuple of various elements, tuples, ... namespace impl { template<typename... Args> struct ConcatTupleHelper { }; template<typename... Args, typename... Args2> struct ConcatTupleHelper<std::tuple<Args...>, std::tuple<Args2...>> { using type = std::tuple<Args..., Args2...>; }; template<typename Arg, typename Arg2> struct ConcatTupleHelper<Arg, Arg2> { using type = std::tuple<Arg, Arg2>; }; template<typename Arg, typename... Args> struct ConcatTupleHelper<Arg, std::tuple<Args...>> { using type = std::tuple<Arg, Args...>; }; template<typename... Args, typename Arg> struct ConcatTupleHelper<std::tuple<Args...>, Arg> { using type = std::tuple<Args..., Arg>; }; } template<typename... Types> using ConcatTupleTypes = typename impl::ConcatTupleHelper<Types...>::type; // StripTuple -> removes void from the tuple, using ConcatTupleTypes namespace impl { template<typename Arg> struct StripTuple { using type = Arg; }; template<typename Arg> using StripTupleType = typename StripTuple<Arg>::type; template<> struct StripTuple<std::tuple<void>> { using type = std::tuple<>; }; template<typename Arg, typename Arg2, typename... Args> struct StripTuple<std::tuple<Arg, Arg2, Args...>> { using type = sys::ConcatTupleTypes<Arg, StripTupleType<std::tuple<Arg2, Args...>>>; }; template<typename Arg2, typename... Args> struct StripTuple<std::tuple<void, Arg2, Args...>> { using type = StripTupleType<std::tuple<Arg2, Args...>>; }; } ´ template<typename Arg> using StripTupleType = impl::StripTupleType; Damn, thats a lot of boilerplate-code though, all of which is needed from my testings. Well, if someone still wants to wrap their head around the underlying algorithmn & propose some better alternative, I'm all for it
  8. So what I want to do sounds pretty simple, but I just can't figure it out: I want to remove all types with a certain characteristic from a tuple. For this example, the condition is actually simple: I want to strip all occurances of "void", so std std::tuple<bool, void, int, void, void, float, void>; becomes: std::tuple<bool, int, float>; I ususally don't have a problem with crazy template-code, but this is just above me. I mean, I know how to split the tuple-declaration into elements, but cannot figure out how to just remove one element while leaving the others intact: template<typename Arg> struct StripTuple { using Type = Arg; }; template<typename Arg, typename... Args> struct StripTuple<std::tuple<Arg, Args...>> { using type = std::tuple<Arg, Args...>>; // ignores StripTuple for all other call; call to StripTuple would be infinite recursion }; template<typename... Args> struct StripTuple<std::tuple<void, Args...>> { using type = StripTuple<Args... >>; }; Any simple solutions (remove-condition = void can be used; doesn't have to work with SFINEA if it doesn't need to)? Alternatively, and to give some context, I'd also be happy not to buld the tuple to have voids to begin with. Though I also can't seem to figure that out for the life of me, and I actually belive it would make the code even more complex than just splitting it into two steps, but let me describe the problem (but beware, if you have a solution that works on the requirements above post this before, as I think the actual problem might be hard to get across for me): For my script-function binding, I recently refactored the type-system to handle types with a specializable trait class, which ie. can be defined for value-types: template<typename Type> struct AttributeSupplier<Type, sys::EnableIf<core::IsTypeSystemType<Type> && !core::IsObject<Type>, void>> { static Type GetAttribute(core::ConstVariableView value) { return value.GetValue<Type>(); } static core::TypeId GetTypeId(void) { return core::generateTypeId<Type>(); } }; The important thing about it, which leads to my "problem", is that this works recursively - when the trait is used, it will unfold the argument-list of the "GetAttributes"-method and forward the aquisition to the next AttributeSupplier. As with GetTypeId, this can be omitted, in which case it will do the same thing - aquire the type-id by unfolding the argument-list and checking those types' suppliers. So what the code that requires stripping the tuple of voids does, is try to access the underlying type of any type(s) it receives, by performing the type-unfolding. Thats necessary for multiple reason, for once the type-system can define a runtime-specific value (ie. EntityHandle which is aquired via EntityID), so the underlying type should be "EntityID". Also, to simplify parsing of a function-declaration, this should allow me to pack all argument-type-ids into a single tuple, unfolding all types (which can also include pair/tuple itself). Stripping the void is for system-supplied values - those do not have a type-id, even after unfolding the entire chain of types, so for the UnderlyingType-definition, they need to be removed. So ie., for a function-signature "void f(int, Entity&, DeltaTime, std::pair<float, bool>)", this should result in the tuple-type "std::tuple<int, Entity&, float, bool>". which is done with this code: struct UnderlyingTypeHelper { using InvalidType = void; template<typename Arg, typename Enable = void> struct Helper { }; // helper for recursion template<typename Arg> using HelperType = typename Helper<Arg>::type; private: // if the arguments trait defines a type-id, we're done template<typename Arg> struct Helper<Arg, sys::EnableIf<HasAttributeTypeId<Arg>, void>> { using type = Arg; }; // values not useable as attributes are meant to be removed/set to void template<typename Arg> struct Helper<Arg, sys::EnableIf<!CanBeAttribute<Arg>, void>> { using type = InvalidType; // !!! here's the out to "void" => this would need to somehow not make it into the tuple created below }; // forwarded type-id => container-structs, runtime-mapped values template<typename Arg> struct Helper<Arg, sys::EnableIf<!IsTuple<Arg> && CanBeAttribute<Arg> && !HasAttributeTypeId<Arg>, void>> { using type = HelperType<AttributeFunctionArgs<Arg>>; }; // tuple => unfold function arguments template<typename... Args> struct Helper<std::tuple<Args...>> { using type = std::tuple<HelperType<Args>...>; }; }; The last specialization is responsible for building the output-tuple, while the others are for eigther recursively unfolding the arguments (AttributeFunctionArgs stores the GetAttribute-signature as a tuple), and selecting when to stop with a type-id-supplied Arg, or just "void" out if we reach a point where Arg is not a valid attribute anymore. So yeah, here's some context, and if anyone feels like torturing their brain around some stupid template-code and comes up with a ingenious solution to that, I wouldn't be unhappy. But I doubt that happens, so a solution to the problem stated way above is already more then enough. Thanks
  9. VK_SNAPSHOT and KEYDOWN

    Hm, not sure why it isn't being called for you, it definately worked for me. After looking through my code though, I noticed I wasn't even installing this hook anymore. From the commit that I wrote, there where some "responsiveness issues", so I just went with using WM_KEYUP for snapshots instead, oh well...
  10. VK_SNAPSHOT and KEYDOWN

    You're right, makes much more sense. That code was pretty much copy paste, as I happen to do with most Win32-related code
  11. VK_SNAPSHOT and KEYDOWN

    I can't remember the exact reason, though I had this problem before (will search the forum-post that will hopefully contain the explanation). In the meanwhile, the solution for me was to install a hook, that checks for that specific keypress: LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { if(nCode >= 0 && nCode == HC_ACTION) { KBDLLHOOKSTRUCT* p = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam); switch(wParam) { case WM_KEYDOWN: if(p->vkCode == VK_SNAPSHOT) input::WindowProcHook::SetRawButtonState(input::Keys::PRINT, true, false); // your code goes here break; } } return CallNextHookEx(impl::hKeyboardHook, nCode, wParam, lParam); } // call this somewhere at program startup void registerPrintKeyHook(void) { impl::hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, lowLevelKeyboardProc, GetModuleHandle(NULL), 0); } EDIT: There you go: this should hopefully explain it
  12. THB, if you are doing the explicit constructor I'd personally go for an explicit conversion method instead: template<typename Type2> Matrix<Type2> To(void) const { return ...; // eigther have an explicit ctor public/private as well or define conversion here } Might just be personal preference, but I find it easier to read/write: Matrix<double> mWorld; matrixTranslate(Matrix<float>(mWorld)); // VS matrixTranslate(mWorld.To<float>()); don't know if there's some objective merit to prefering the explicit ctor, but I've been adopting the method-approach for my projects' math classes so far, just though I'd throw it in there.
  13. Yeah, you could eigther add a templated copy ctor, or a templated multiplication operator: template<typename T2> Matrix(const Matrix<T2>& m) { } template<typename T2> Matrix operator*(const Matrix<T2>& m) { } The ctor is more general and extensible, though can result in unwanted conversions, especially if you do not make it explicit. Btw, out of interest, is there really a general compelling reason to have the world-matrix as double? I've never seen or heard of such a thing, always all matrices have had the same type of float.
  14. Visual Studio, pls

    Ok, short but sweet. I was simplifying the code regarding my plugins DLL-entry point export-functions, mainly going from a h/cpp-pair to just a cpp (the header was pretty redudant). Two plugins to test with, one with only one entry-point (game code), the other with two (game code + editor code). The first generates the symbols, the second doesn't even process the Export.cpp-file. What the hell? Long story short, I went through a lot of nonsensical options, when it turns out that Visual Studio has an "element type" attribute for files. Turns out I deleted Export.cpp, afterwards renamed Export.h to Export.cpp and then this internal flag was still set to "C/C++ header" instead of "C/C++ compiler". Yes, thats how VS determines if it compiles the file and not the ending. And no, that flag doesn't change when you rename the file, even in the IDE. Thanks for wasting an hour of my life, the moral here is - never change your filetypes? Yikes
  15. Ah, the generateSortFunction-idea is just what I was looking for, thanks Unfortunately I really cannot/do not want to use std::function here (aside from its overhead it also disallowes constexpr here too), and while I could simply template the generateSortFunction, it would still require me to store the result as std::function due to the capture. I think I found a "better" solution though: using CompareFunction = bool(*)(const SortData& left, const SortData& right); // make the generateSortFunction templated with the adress of our Sort-function as non-type argument template<CompareFunction Sorter> constexpr auto generateSortFunction(void) { return [](SortingVector& vData) { std::stable_sort(vData.begin(), vData.end(), Sorter); }; } constexpr auto generateSortFunctions(void) { // we can just store the lambda directly as a function-pointer constexpr CompareFunction frontToBack = [](const SortData& left, const SortData& right) { return left.z > right.z; }; constexpr CompareFunction backToFront = [](const SortData& left, const SortData& right) { return left.z < right.z; }; constexpr CompareFunction texture = [](const SortData& left, const SortData& right) { return left.pTexture < right.pTexture; }; using SortFunction = void(*)(SortingVector& vSortData); // now those function-pointers can be used to statically generate different overload of generateSortFunction constexpr std::array<SortFunction, 3> vFunctions = { generateSortFunction<backToFront>(), generateSortFunction<frontToBack>(), generateSortFunction<texture>(), }; return vFunctions; } I'm storing the lambda directly inside a function-pointer and pass that to the generateSortFunction as a non-type template parameter. Wohoo for modern C++ I'll just have to check whether this actually allows the compiler to inline the sorting-function into std::stable_sort, but I'm pretty certain it can.