Max*_*hof 17 c++ forward-declaration language-lawyer variadic-templates c++17
I have a variadic template that inherits from all template arguments:
template <typename... Ts>
struct derived : Ts...
{
};
Run Code Online (Sandbox Code Playgroud)
I would also like to have a facility for expressing the type of "existing derived with added template arguments". My attempt at this is:
// Do not ODR-use (goes in namespace impl or similar)!
template<class ... NewInputs, class ... ExistingInputs>
auto addedHelper(const derived<ExistingInputs...>&)
-> derived<ExistingInputs..., NewInputs...>;
template<class ExistingInput, class ... NewInputs>
using Added = decltype(addedHelper<NewInputs...>(std::declval<ExistingInput>()));
Run Code Online (Sandbox Code Playgroud)
As a simple example, Added<derived<A, B>, C> should be derived<A, B, C>. I use the helper function for template argument deduction of the first parameter pack.
My problem: For some reason, I can use this successfully with incomplete types if derived has been forward declared, but not if it was defined.
Why does this code not compile:
#include <utility>
template <typename... Ts>
struct derived : Ts...
{};
template<class ... NewInputs, class ... ExistingInputs>
auto addedHelper(const derived<ExistingInputs...>&)
-> derived<ExistingInputs..., NewInputs...>;
template<class ExistingInput, class ... NewInputs>
using Added = decltype(addedHelper<NewInputs...>(std::declval<ExistingInput>()));
struct A;
struct B;
struct C;
// Goal: This forward declaration should work (with incomplete A, B, C).
auto test(derived<A, B> in) -> Added<decltype(in), C>;
struct A {};
struct B {};
struct C {};
void foo()
{
auto abc = test({});
static_assert(std::is_same_v<decltype(abc), derived<A, B, C>>, "Pass");
}
Run Code Online (Sandbox Code Playgroud)
Whereas this code does compile:
#include <utility>
template <typename... Ts>
struct derived;
template<class ... NewInputs, class ... ExistingInputs>
auto addedHelper(const derived<ExistingInputs...>&)
-> derived<ExistingInputs..., NewInputs...>;
template<class ExistingInput, class ... NewInputs>
using Added = decltype(addedHelper<NewInputs...>(std::declval<ExistingInput>()));
struct A;
struct B;
struct C;
// Goal: This forward declaration should work (with incomplete A, B, C).
auto test(derived<A, B> in) -> Added<decltype(in), C>;
template <typename... Ts>
struct derived : Ts...
{};
struct A {};
struct B {};
struct C {};
void foo()
{
auto abc = test({});
static_assert(std::is_same_v<decltype(abc), derived<A, B, C>>, "Pass");
}
Run Code Online (Sandbox Code Playgroud)
For convenience, here are both cases at once (comment in/out #define FORWARD_DECLARED): https://godbolt.org/z/7gM52j
I do not understand how code could possibly become illegal by replacing a forward declaration by the respective definition (which would otherwise just come later).
Evg的观察击中了头:这里的问题是ADL。这实际上是我遇到这个问题时遇到的相同问题。
问题是这样的:我们在这里有一个不合格的电话:
template<class ExistingInput, class ... NewInputs>
using Added = decltype(addedHelper<NewInputs...>(std::declval<ExistingInput>()));
// ^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
我们知道它是一个功能模板,因为我们可以通过常规查找找到它,因此我们不必处理整个“是<运算符还是模板引入程序”问题。但是,由于这是不合格的调用,因此我们还必须执行依赖于参数的查找。
ADL需要研究所有参数的关联命名空间,这似乎很好-我们不需要完整的类型。但是ADL 还需要寻找类中定义的潜在好友功能和功能模板。毕竟,这需要工作:
struct X {
friend void foo(X) { }
};
foo(X{}); // must work, call the hidden friend defined within X
Run Code Online (Sandbox Code Playgroud)
结果,在有问题的电话中:
auto test(derived<A, B> in) -> Added<decltype(in), C>;
Run Code Online (Sandbox Code Playgroud)
我们必须实例化derived<A, B>...,但是该类型继承自两个不完整的类,而我们不能这样做。那就是问题所在,那就是我们失败的地方。
这就是为什么前向声明版本有效的原因。template <typename... T> struct derived;是不完整的,因此仅尝试在其中查找朋友功能就不会发现任何内容-我们无需实例化任何其他内容。
同样,一个derived完整但实际上不是从任何内容派生的版本也可以使用。
值得庆幸的是,这在Evg建议的情况下可以解决。拨打合格电话:
template<class ExistingInput, class ... NewInputs>
using Added = decltype(::addedHelper<NewInputs...>(std::declval<ExistingInput>()));
Run Code Online (Sandbox Code Playgroud)
这样可以避免您甚至不需要的ADL。最好的情况是,您要避免做对您没有好处的事情。糟糕的情况是,您的代码无法编译。邪恶的情况,对于某些输入,您不小心完全调用了另一个函数。
或者只是使用Boost.Mp11 mp_push_back
| 归档时间: |
|
| 查看次数: |
308 次 |
| 最近记录: |