1

I trying to create a simple test for type that derive from a specific templated base. Here is the code.

#include <string>

template <class... T>
struct bar { };

struct foo : bar<>
{
    template <class... T>
    foo(T&&...) { }
};

template <class T>
struct is_bar {
private:
    template <class... U>
    static std::true_type  test(bar<U...>);
    static std::false_type test(...);
public:
    static constexpr bool value = decltype(test(std::declval<T>()))::value;
};

template <class T>
void test(T&&) {
    static_assert(is_bar<std::decay_t<T>>::value);
}

int main()
{
    // Test 1: works
    test(foo(std::string()));

    // Test 2: works
    std::string s;
    foo f2(s);
    test(f2);

    // Test 3: not working
    foo f3(std::string());
    test(f3);
}

Tests 1 and 2 works fine. See comments. Can someone point out why test 3 result in a false assert?

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • tl;dr of the dupe: `f3` is actually a function declaration. Hence it's not even of a class type. – StoryTeller - Unslander Monica Dec 19 '19 at 22:06
  • @Vladimir how Is the code even compiling? What compiler do you use? – Ingo Mi Dec 19 '19 at 22:08
  • @Ivanovic `g++ -std=c++14 test.cpp` – Vladimir Talybin Dec 19 '19 at 22:22
  • @Vladimir [jack@jacks test]$ g++ -std=c++14 main.cpp main.cpp: In instantiation of ‘void test(T&&) [with T = foo (&)(std::__cxx11::basic_string (*)())]’: main.cpp:39:12: required from here main.cpp:24:44: error: static assertion failed 24 | static_assert(is_bar>::value); | ^~~~~ (on Arch Linux, latest) Just saw Daniel added it to his answer. (same with gcc, the qt compiler, the make file) – Ingo Mi Dec 19 '19 at 22:27
  • @Ivanovic That is what this question is about. It fail to compile because of test nr. 3. Compiler sees f3 as function, but I mean to pass an empty string to constructor. See the answer below. – Vladimir Talybin Dec 19 '19 at 22:32

1 Answers1

0

Welcome to the most vexing parse: f3 is a function. This is what a compiler with warnings enabled says:

prog.cpp:38:11: warning: parentheses were disambiguated as a function declaration [-Wvexing-parse]
 foo f3(std::string());
 ^~~~~~~~~~~~~~~ 
prog.cpp:38:12: note: add a pair of parentheses to declare a variable
 foo f3(std::string());
        ^
        (            )

Thus std::declval<T>() in your test is a function pointer, which is clearly not convertible to bar<U>

Daniel Jour
  • 15,896
  • 2
  • 36
  • 63
  • Yes, I figured this out from C++ insights. Should really use -Wall while compiling :) But how this differ from test 1? Why compiler do not see that as function declaration? – Vladimir Talybin Dec 19 '19 at 22:19
  • @Vladimir There is no enlightened answer, it's just because it's not defined as valid syntax by the C++ language... So it is so, by definition of the language. f you do have an expression within then it is valid like std::string(0) (https://stackoverflow.com/questions/1424510/my-attempt-at-value-initialization-is-interpreted-as-a-function-declaration-and) – Ingo Mi Dec 19 '19 at 22:31
  • @Vladimir Please don't forget to mark your answer as solved. – Ingo Mi Dec 23 '19 at 18:43