Thread: Trouble with SFINAE

  1. #1
    Registered User
    Join Date
    Jun 2014
    Posts
    66

    Trouble with SFINAE

    Hey folks,

    I'm currently trying to make my container wrapper only define some specific member functions if they are supported by the underlying container.

    Code:
    template<typename Type, template<typename...> typename Container>
    class container {
    public:
        using size_type=typename Container<Type>::size_type;
        
        auto at(size_type position)
            -> decltype(std::declval<Container<Type>>()[std::declval<size_type>()]);
    };
    Sadly it doesn't really work at the moment: my compiler throws hard errors instead of silently removing the overload...

    Code:
    int main()
    {
        container<int, std::vector> first; // fine
        container<int, std::set> second; // hard error: no operator[] defined
    }
    It would be nice if someone could point out my mistake! Thanks
    Last edited by milli-961227; 07-13-2015 at 09:40 AM.

  2. #2
    Registered User
    Join Date
    Dec 2013
    Posts
    241
    have you considered using std::enable_if ?

  3. #3
    Registered User
    Join Date
    Jun 2014
    Posts
    66
    Yes, I tried and failed... The problem with `std::enable_if' is that it requires a boolean parameter, and I didn't manage to convert a syntax query to a boolean value. I also played around a bit with `std::result_of', but it doesn't work either:

    Code:
    // This gives me a bunch of compiler errors
    auto at(size_type position) -> typename std::result_of<decltype(&Container<Type>::operator[])(Container<Type>, std::declval<size_type>())>::type;
    I also found solutions like this one, but they seem to be a bit of overkill to me.
    Last edited by milli-961227; 07-13-2015 at 10:09 AM.

  4. #4
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    O_o

    You aren't giving the compiler an option.

    The expression `decltype(std::declval<Container<Type>>()[std::declval<size_type>()])` could be reduced to `decltype(Container<Type>()[0])` in most cases. The expression `decltype(Container<Type>()[0])` does not result in simple substitution failure because the expression is not being evaluated in the context of a template function. The SFINAE technique works for code that only attempts to look into a type in the appropriate context of expanding a template function. You simply have a method which belongs to a template class; the code fails for the same reason `decltype(std::declval<std::set<int>>()[std::declval<size_type>()])` fails.

    I also found solutions like this one, but they seem to be a bit of overkill to me.
    You may not like the code, but the approach of evaluating the expression in the context of a template function is correct.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  5. #5
    Registered User
    Join Date
    Jun 2014
    Posts
    66
    The SFINAE technique works for code that only attempts to look into a type in the appropriate context of expanding a template function.
    Thanks, that's the answer! I'll try it with something like that:

    c++ - void_t "can implement concepts"? - Stack Overflow
    Concept Checking in C++11 | Eric Niebler

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    The answer is typically

    Code:
    template<typename T>
    struct foo
    {
        template<typename T2 = T>
        auto bar() -> std::enable_if_t</* something something referencing T2 */, void> {}
    };
    By using the extra template, the function will only be instantiated when called and then SFINAE kicks in.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Registered User
    Join Date
    Jun 2014
    Posts
    66
    By using the extra template, the function will only be instantiated when called and then SFINAE kicks in.
    Ah, this makes sense I guess... And it also leads to a much cleaner solution in my case:

    Code:
    template<typename Type, template<typename...> typename Container>
    class container {
    public:
        using size_type=typename Container<Type>::size_type;
    
        template<typename Storage=Container<Type>>
        auto operator[](size_type position) -> decltype(Storage()[0]); // no need of `std::enable_if' or `std::result_of' here
    };
    
    int main()
    {
        container<int, std::vector> first; // fine
        auto first_element=first[0]; // fine: operator defined
    
        container<int, std::set> second; // fine
        auto second_element=second[0]; // error: operator not defined
    }
    Thank you guys again, your help is highly appreciated!

  8. #8
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    By using the extra template, the function will only be instantiated when called and then SFINAE kicks in.
    O_o

    For the sake of information, the extra template parameter does not have to be a part of the method signature.

    A template method can't be virtual so you'll may occasionally need to move the extra template parameter into another class which can then be inherited.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. SFINAE trouble
    By Elysia in forum C++ Programming
    Replies: 4
    Last Post: 09-04-2014, 12:02 PM
  2. SFINAE fun (or failure...)
    By Elysia in forum C++ Programming
    Replies: 25
    Last Post: 05-15-2013, 03:17 PM
  3. DLL trouble
    By Redshrimp2021 in forum C++ Programming
    Replies: 4
    Last Post: 08-07-2007, 02:26 PM
  4. trouble
    By firefly in forum C++ Programming
    Replies: 4
    Last Post: 06-28-2005, 04:21 PM
  5. Please Help Me,i'm In Trouble
    By ektrem^gal in forum C++ Programming
    Replies: 5
    Last Post: 04-30-2003, 04:47 AM