在C++中调用嵌套的静态成员

huangapple go评论64阅读模式
英文:

Calling nested static members in c++

问题

template<typename TH, typename ... TGs>
static void static_recursive(TGs &... gs) {
    MyStruct::st_printno<TH>();
}
英文:

I am creating a program that calls a nested template function. It works fine if the nested template function is a class member (i.e. by adding this->template). But how to make it work in the static case (i.e. the ???)

The code example is a bit complex, but the most important lines are the difference between the this-&gt;template test_recursive_sub&lt;TH&gt;(gs...);and the static version ??? test_recursive_sub&lt;TH&gt;(gs...);in calling a nested template function in the same class. What has to replace the ???

#include &lt;cstdint&gt;
#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;vector&gt;

struct TestObject1 {
	using Type = int;
};

struct TestObject2 {
	using Type = int;
};

struct TestObject3 {
	using Type = int;
};

struct MyStruct {
	template&lt;typename TH&gt;
	void printno() {
		typename TH::Type num = 100;
		std::cout &lt;&lt; num &lt;&lt; std::endl;
	}

	template&lt;typename TH&gt;
	void static st_printno() {
		typename TH::Type num = 100;
		std::cout &lt;&lt; num &lt;&lt; std::endl;
	}

	template&lt;typename TH, typename ... TG&gt;
	void test_recursive_sub(TG &amp;... gs) {
		printno&lt;TH&gt;();
	}

	template&lt;typename TH, typename ... TG&gt;
	void test_recursive(TG &amp;... gs) {
		this-&gt;template test_recursive_sub&lt;TH&gt;(gs...);
	}

	template&lt;typename TH, typename ... TGs&gt;
	static void recursive_sub(TGs &amp;... gs) {
		MyStruct::st_printno&lt;TH&gt;();
	}

	template&lt;typename TH, typename ... TGs&gt;
	static void static_recursive(TGs &amp;... gs) {
		??? test_recursive_sub&lt;TH&gt;(gs...);
	}
};

int static_template_nesting() {

	TestObject1 to1;
	TestObject2 to2;

	MyStruct ro1;

	ro1.test_recursive&lt;TestObject2&gt;(to1, to1, to2);
	ro1.test_recursive&lt;TestObject3&gt;(to2);
	MyStruct::static_recursive&lt;TestObject2&gt;(to1, to1, to2);
	MyStruct::static_recursive&lt;TestObject3&gt;(to2);

	return 0;
}

答案1

得分: 2

你对它的写法,没有递归(没有函数调用自身)。
此外,静态函数只能调用静态函数(非静态应该由对象调用)。
模板参数没有正确声明或使用。
首先声明一个函数的通用版本,该版本将接受第一个参数(head)和其他参数(tails)。你似乎已经在这条路上了。
如果tails中的参数数量非零,那么你可以递归:处理head,然后将tails转发到相同的函数,而无需指定模板参数:函数将自行推断它们。
如果tails中的参数数量为零,则调用特定的实现。
在C++17之前,你将为每种情况编写一个函数,并使用SFINAE保留一个合法的重载。你可以通过在模板参数中添加std::enable_if_t,来完成这个操作,对于单参数情况,它将无效。
自C++17以来,情况变得更简单了,只需编写一个带有if constexpr的单一函数,就像编写传统递归一样。
这里是修复:

#include &lt;cstdint&gt;
#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;vector&gt;

// 在C++14之前将使用std::enable_if
#include &lt;type_traits&gt;

struct TestObject1 {
    using Type = int;
};

struct TestObject2 {
    using Type = int;
};

struct TestObject3 {
    using Type = int;
};

struct MyStruct {
    template &lt;typename TH&gt;
    void printno() {
        typename TH::Type num = 100;
        std::cout &lt;&lt; num &lt;&lt; std::endl;
    }

    template &lt;typename TH&gt;
    void static st_printno() {
        typename TH::Type num = 100;
        std::cout &lt;&lt; num &lt;&lt; std::endl;
    }

    template &lt;typename TH, typename... TG&gt;
    void test_recursive_sub(TG &amp;...gs) {
        printno&lt;TH&gt;();
    }

    template &lt;typename TH, typename... TG&gt;
    void test_recursive(TG &amp;...gs) {
        this-&gt;template test_recursive_sub&lt;TH&gt;(gs...);
    }

    template &lt;typename TH, typename... TGs&gt;
    static void recursive_sub(TGs &amp;...gs) {
        MyStruct::st_printno&lt;TH&gt;();
    }

    // C++14版本
    // 仅对多参数重载
    // 如果只有一个参数,SFINAE将消除它
    template &lt;typename TH, typename... TGs,
              std::enable_if_t&lt;(sizeof...(TGs) &gt; 0), bool&gt; = true&gt;
    static void static_recursive(TH &amp;head, TGs &amp;...tail) {
        std::cout &lt;&lt; &quot;处理一个参数,然后 &quot; &lt;&lt; sizeof...(TGs) &lt;&lt; &quot; 个参数&quot;
                  &lt;&lt; std::endl;
        static_recursive(tail...);
    }
    template &lt;typename TH&gt;
    // 仅对单参数重载
    static void static_recursive(TH &amp;head) {
        std::cout &lt;&lt; &quot;处理单个元素&quot; &lt;&lt; std::endl;
    }
    // C++17版本
    // template &lt;typename TH, typename... TGs&gt;
    // static void static_recursive(TH &amp;head, TGs &amp;...tail) {
    //     if constexpr (sizeof...(TGs) &gt; 0) {
    //         std::cout &lt;&lt; &quot;处理一个参数,然后 &quot; &lt;&lt; sizeof...(TGs) &lt;&lt; &quot; 个参数&quot;
    //                   &lt;&lt; std::endl;
    //         static_recursive(tail...);
    //     } else {
    //         std::cout &lt;&lt; &quot;处理单个元素&quot; &lt;&lt; std::endl;
    //     }
    // }
};

int main() {
    TestObject1 to1;
    TestObject2 to2;

    MyStruct ro1;

    ro1.test_recursive&lt;TestObject2&gt;(to1, to1, to2);
    ro1.test_recursive&lt;TestObject3&gt;(to2);
    // 无需提供模板参数,它们会被推断
    MyStruct::static_recursive(to1, to1, to2);
    MyStruct::static_recursive(to2);

    return 0;
}
英文:

The way you right it, there is no recursion (no function calling itself).
Besides, a static function can only call a static function (non static should be called by an object).
The template arguments were not declared neither used properly.
First declare a generic version of the function that will take a first argument (head) and the other ones (tails). You seemed to be on this track already.
If the number of arguments in tails is non zero then you can recurse: process head then forward tails to the same function without specifying template arguments: the function will deduce them by itself.
If the number of arguments in tails is zero, you call a special implementation.
Before C++17, you will write a function for each case and use SFINAE to leave only one overload well-formed. You can do that by adding an std::enable_if_t, in the template parameters, that will be invalid for the single argument case.
Since C++17 it's easier, simply write a single function with an if constexpr, as you would write a classical recursion.
Here is the fix:

#include &lt;cstdint&gt;
#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;vector&gt;

// will use std::enable_if until C++14
#include &lt;type_traits&gt;

struct TestObject1 {
    using Type = int;
};

struct TestObject2 {
    using Type = int;
};

struct TestObject3 {
    using Type = int;
};

struct MyStruct {
    template &lt;typename TH&gt;
    void printno() {
        typename TH::Type num = 100;
        std::cout &lt;&lt; num &lt;&lt; std::endl;
    }

    template &lt;typename TH&gt;
    void static st_printno() {
        typename TH::Type num = 100;
        std::cout &lt;&lt; num &lt;&lt; std::endl;
    }

    template &lt;typename TH, typename... TG&gt;
    void test_recursive_sub(TG &amp;...gs) {
        printno&lt;TH&gt;();
    }

    template &lt;typename TH, typename... TG&gt;
    void test_recursive(TG &amp;...gs) {
        this-&gt;template test_recursive_sub&lt;TH&gt;(gs...);
    }

    template &lt;typename TH, typename... TGs&gt;
    static void recursive_sub(TGs &amp;...gs) {
        MyStruct::st_printno&lt;TH&gt;();
    }

    // C++14 version
    // overload for multiple argument only
    // SFINAE will eliminate it if there is only one argument
    template &lt;typename TH, typename... TGs,
              std::enable_if_t&lt;(sizeof...(TGs) &gt; 0), bool&gt; = true&gt;
    static void static_recursive(TH &amp;head, TGs &amp;...tail) {
        std::cout &lt;&lt; &quot;process an arg then &quot; &lt;&lt; sizeof...(TGs) &lt;&lt; &quot; args&quot;
                  &lt;&lt; std::endl;
        static_recursive(tail...);
    }
    template &lt;typename TH&gt;
    // overload for single argument only
    static void static_recursive(TH &amp;head) {
        std::cout &lt;&lt; &quot;process single element&quot; &lt;&lt; std::endl;
    }
    // C++17 version
    // template &lt;typename TH, typename... TGs&gt;
    // static void static_recursive(TH &amp;head, TGs &amp;...tail) {
    //     if constexpr (sizeof...(TGs) &gt; 0) {
    //         std::cout &lt;&lt; &quot;process an arg then &quot; &lt;&lt; sizeof...(TGs) &lt;&lt; &quot; args&quot;
    //                   &lt;&lt; std::endl;
    //         static_recursive(tail...);
    //     } else {
    //         std::cout &lt;&lt; &quot;process single element&quot; &lt;&lt; std::endl;
    //     }
    // }
};

int main() {
    TestObject1 to1;
    TestObject2 to2;

    MyStruct ro1;

    ro1.test_recursive&lt;TestObject2&gt;(to1, to1, to2);
    ro1.test_recursive&lt;TestObject3&gt;(to2);
    // no need to give template arguments, they are deduced
    MyStruct::static_recursive(to1, to1, to2);
    MyStruct::static_recursive(to2);

    return 0;
}

Live

huangapple
  • 本文由 发表于 2023年6月1日 14:52:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76379337.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定