最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c++ - no matching function call error when introducing a namespace - Stack Overflow

programmeradmin1浏览0评论

The following code works as expected:

template <int N> struct Int {
    constexpr auto dec() const -> Int<N - 1> {
        return {};
    }
    constexpr operator int() const {
        return N;
    }
};

constexpr auto fib(Int<0>) -> Int<0> {
    return {};
}
template <int N> constexpr auto fib(Int<N> n) -> decltype(fib(n.dec())) {
    return {};
}

static_assert(fib(Int<2>()) == 0);

However, if I introduce a namespace for Int, it suddenly fails on both GCC and Clang:

namespace foo {
    template <int N> struct Int {
        constexpr auto dec() const -> Int<N - 1> {
            return {};
        }
        constexpr operator int() const {
            return N;
        }
    };
}

template <int N> using Int = foo::Int<N>;

constexpr auto fib(Int<0>) -> Int<0> {
    return {};
}
template <int N> constexpr auto fib(Int<N> n) -> decltype(fib(n.dec())) {
    return {};
}

static_assert(fib(Int<2>()) == 0);

With the following error message:

<source>:21:15: error: no matching function for call to 'fib'
   21 | static_assert(fib(Int<2>()) == 0);
      |               ^~~
<source>:14:16: note: candidate function not viable: no known conversion from 'Int<2>' to 'Int<0>' for 1st argument
   14 | constexpr auto fib(Int<0>) -> Int<0> {
      |                ^   ~~~~~~
<source>:17:33: note: candidate template ignored: substitution failure [with N = 2]: call to function 'fib' that is neither visible in the template definition nor found by argument-dependent lookup
   17 | template <int N> constexpr auto fib(Int<N> n) -> decltype(fib(n.dec())) {
      |                                 ^                         ~~~

Can someone explain what is going on here? Why does introducing a namespace create a compiler error?

The following code works as expected:

template <int N> struct Int {
    constexpr auto dec() const -> Int<N - 1> {
        return {};
    }
    constexpr operator int() const {
        return N;
    }
};

constexpr auto fib(Int<0>) -> Int<0> {
    return {};
}
template <int N> constexpr auto fib(Int<N> n) -> decltype(fib(n.dec())) {
    return {};
}

static_assert(fib(Int<2>()) == 0);

However, if I introduce a namespace for Int, it suddenly fails on both GCC and Clang:

namespace foo {
    template <int N> struct Int {
        constexpr auto dec() const -> Int<N - 1> {
            return {};
        }
        constexpr operator int() const {
            return N;
        }
    };
}

template <int N> using Int = foo::Int<N>;

constexpr auto fib(Int<0>) -> Int<0> {
    return {};
}
template <int N> constexpr auto fib(Int<N> n) -> decltype(fib(n.dec())) {
    return {};
}

static_assert(fib(Int<2>()) == 0);

With the following error message:

<source>:21:15: error: no matching function for call to 'fib'
   21 | static_assert(fib(Int<2>()) == 0);
      |               ^~~
<source>:14:16: note: candidate function not viable: no known conversion from 'Int<2>' to 'Int<0>' for 1st argument
   14 | constexpr auto fib(Int<0>) -> Int<0> {
      |                ^   ~~~~~~
<source>:17:33: note: candidate template ignored: substitution failure [with N = 2]: call to function 'fib' that is neither visible in the template definition nor found by argument-dependent lookup
   17 | template <int N> constexpr auto fib(Int<N> n) -> decltype(fib(n.dec())) {
      |                                 ^                         ~~~

Can someone explain what is going on here? Why does introducing a namespace create a compiler error?

Share Improve this question asked Mar 15 at 10:52 eyelasheyelash 3,78827 silver badges34 bronze badges 3
  • 4 Note: clang fails with your first version as well, see demo. – wohlstad Commented Mar 15 at 12:21
  • 1 Where would the compiler look for functions taking a foo::Int parameter? Will it find any there? See Argument Dependent Lookup – BoP Commented Mar 15 at 13:45
  • 2 I think It is "indetemined" if compiler instantiate fib<0> if overload doesn't select it; but instantiate it lead to (negative) overflow. – Jarod42 Commented Mar 15 at 14:16
Add a comment  | 

1 Answer 1

Reset to default 4

Functions can be recursive, of course, but they can’t be recursive in their own return type (even in the rare instance that it would be meaningful) because name lookup doesn’t consider them:

auto f() -> std::conditional_t<true,void,decltype(f())*>;  // f undeclared

With function templates, one can construct reasonable-looking recursions like yours, but name lookup still can’t find the same template—except via ADL, of course, which is the usual culprit in weird behavior like this.

发布评论

评论列表(0)

  1. 暂无评论