opDispatch和编译时参数
如何使用opDispatch将编译时参数转发给方法。见下面的代码:opDispatch和编译时参数,d,D,如何使用opDispatch将编译时参数转发给方法。见下面的代码: import std.stdio; struct B{ auto p1(T)(T arg) { writeln( "p1: ", arg ); } auto p2(T, int C)(T s) { writeln( "p2: ", s, " / ", C); } } struct C(T) { T b; auto opDispatch(stri
import std.stdio;
struct B{
auto p1(T)(T arg) {
writeln( "p1: ", arg );
}
auto p2(T, int C)(T s) {
writeln( "p2: ", s, " / ", C);
}
}
struct C(T) {
T b;
auto opDispatch(string s, Args...)(Args args) {
mixin("b."~s)(args);
}
}
void main() {
C!B b;
//fine: compiler is smart enough
b.p1("abc");
//oops: "no property 'p2' for type ..."
b.p2!(int, 10)(5);
B origB;
//fine:
origB.p2!(int, 10)(5);
}
编辑
用struct替换类:使用
new
避免使用CTFE进行字段初始化。这与我的问题无关 您需要使用同名模板模式,并在采用常规opDispatch字符串参数的外部opDispatch模板中使用带有编译时参数的opDispatch函数。您还可以有多个遵循常规重载规则的内部opDispatch函数(和字段)
import std.stdio;
struct Foo {
public template opDispatch(string name) {
public string opDispatch() {
return name;
}
public T opDispatch(T)() {
return T.init;
}
public string opDispatch(T)(string s) {
return name ~ ' ' ~ T.stringof ~ ' ' ~ s;
}
}
}
void main()
{
Foo foo;
writeln( foo.bar );
writeln( foo.baz!int );
writeln( foo.foo!Foo("foo") );
}
生成输出:
bar
0
foo Foo foo
DPaste链接:如果像Adam D.Ruppe的回答所建议的那样,
opDispatch确实不可能做到这一点,那么你唯一的办法可能是使用字符串混音,它有点难看,但功能非常强大。除非使用opDispatch
是一项硬要求,否则字符串混合可能是唯一的方法
幸运的是,要做的大部分工作是(而且比你想象的要复杂得多)。代码本身很复杂,但您只需执行以下操作:
import std.stdio;
class B{
auto p1(T)(T arg) {
writeln( "p1: ", arg );
}
auto p2(T, int C)(T s) {
writeln( "p2: ", s, " / ", C);
}
}
class C(T) {
T b = new T;
mixin(forwardToMember!(b, "p1", "p2"));
}
void main() {
auto b = new C!(B)();
b.p1("abc");
//This now compiles and correctly forwards to b.b.p2
b.p2!(int, 10)(5);
}
我已经包括了下面的代码和所有单元测试。需要注意的是,forwardToMember
目前不支持常规函数的重载;它只会选择它找到的指定函数的第一个实例。但是,我认为它们应该适用于模板函数
import std.traits;
import std.meta;
private alias isSomeStringType(alias str) = isSomeString!(typeof(str));
template forwardToMember(alias member, symbols...)
if (symbols.length > 0 && allSatisfy!(isSomeStringType, symbols))
{
static if (symbols.length == 1)
{
static assert(hasMember!(typeof(member), symbols[0]),
"Cannot dispatch: member '" ~ member.stringof ~
"' does not support method '" ~ symbols[0] ~ "'");
enum forwardToMember = genWrapperMixin!(member, symbols[0]);
}
else
{
enum forwardToMember = forwardToMember!(member, symbols[0]) ~ forwardToMember!(member, symbols[1..$]);
}
}
private enum SymbolKind
{
function_,
property,
templateFunction,
fieldFunction,
field,
aliasableSym,
}
//Ugly hack but there's no other way to do this
private template isTemplateFunction(f...)
if (f.length == 1)
{
import std.algorithm: among, balancedParens, canFind, count;
static if (!__traits(isTemplate, f[0]))
{
enum isTemplateFunction = false;
}
else
{
enum fstr = f[0].stringof;
//A template function's .stringof is of the format <function name>(<template args>)(<function args>)
//so match on the number of brackets to determine whether it's a template function or not
enum isTemplateFunction = __traits(isTemplate, f)
&& fstr.balancedParens('(', ')')
&& (fstr.canFind("if")
|| fstr.count!(c => cast(bool)c.among!('(', ')')) == 4);
}
}
private template getSymbolKind(Aggregate, string symbol)
{
import std.traits;
import std.typetuple;
enum getMemberMixin = "Aggregate." ~ symbol;
//Appears in Aggregate.tupleof so it must be a field
static if (staticIndexOf!(symbol, FieldNameTuple!Aggregate) > -1)
{
//Check if it's a regular field or a function pointer
static if (isSomeFunction!(mixin(getMemberMixin)))
enum getSymbolKind = SymbolKind.fieldFunction;
else
enum getSymbolKind = SymbolKind.field;
}
else
{
static if (isSomeFunction!(mixin(getMemberMixin))
&& !__traits(isStaticFunction, mixin(getMemberMixin))
|| isTemplateFunction!(mixin(getMemberMixin)))
{
static if (isTemplateFunction!(mixin(getMemberMixin)))
enum getSymbolKind = SymbolKind.templateFunction;
else static if (functionAttributes!(mixin(getMemberMixin)) & FunctionAttribute.property)
enum getSymbolKind = SymbolKind.property;
else
enum getSymbolKind = SymbolKind.function_;
}
//If it's not a member function/property then it should be an aliasable static symbol
else static if (__traits(compiles, { alias _ = Alias!(mixin(getMemberMixin)); }))
enum getSymbolKind = SymbolKind.aliasableSym;
else
static assert(0, "Error: " ~ Aggregate.stringof ~ "." ~ symbol ~ " is not a member function, field, or aliasable symbol");
}
}
private template genWrapperMixin(alias member, string symbol)
{
import std.algorithm: among;
import std.string: format;
enum symbolKind = getSymbolKind!(typeof(member), symbol);
static if (symbolKind.among!(SymbolKind.function_, SymbolKind.property, SymbolKind.fieldFunction))
{
alias MethodType = FunctionTypeOf!(mixin("member." ~ symbol));
enum funAttrs = functionAttributes!MethodType;
enum methodIsStatic = __traits(isStaticFunction, mixin("member." ~ symbol));
enum funAttrStr = getFunctionAttributeStr(funAttrs) ~ (methodIsStatic ? " static" : "");
//Workaround Issue 14913
enum returnStr = funAttrs & FunctionAttribute.return_ ? "return" : "";
enum genWrapperMixin = q{
%3$s
auto ref %2$s(ParameterTypeTuple!(FunctionTypeOf!(%1$s.%2$s)) args) %4$s
{
import std.functional: forward;
return %1$s.%2$s(forward!args);
}
}
.format(member.stringof, symbol, funAttrStr, returnStr);
}
else static if (symbolKind == SymbolKind.templateFunction)
{
enum genWrapperMixin = q{
template %2$s(TemplateArgs...)
{
auto ref %2$s(FunArgs...)(auto ref FunArgs args)
{
import std.functional: forward;
return %1$s.%2$s!(TemplateArgs)(forward!args);
}
}
}
.format(member.stringof, symbol);
}
else static if (symbolKind == SymbolKind.field)
{
alias FieldType = typeof(mixin("member." ~ symbol));
alias FA = FunctionAttribute;
enum attrStr = getFunctionAttributeStr(FA.pure_ | FA.nothrow_ | FA.safe | FA.nogc);
enum genWrapperMixin = q{
@property %3$s %4$s %1$s()
{
return %2$s.%1$s;
}
@property %3$s void %1$s(%4$s val)
{
%2$s.%1$s = val;
}
}
.format(symbol, member.stringof, attrStr, FieldType.stringof);
}
else static if (symbolKind == SymbolKind.aliasableSym)
{
enum genWrapperMixin = q{
alias %1$s = %2$s.%1$s;
}
.format(symbol, member.stringof);
}
else
static assert(member.stringof ~ "." ~ symbol ~ " has unexpected kind '" ~ symbolKind.to!string);
}
private string getFunctionAttributeStr(FunctionAttribute funAttrs)
{
import std.algorithm: among, filter, joiner, map, strip;
import std.conv: to;
string funAttrStr;
with (FunctionAttribute)
{
funAttrStr = [EnumMembers!FunctionAttribute]
.filter!(e => (funAttrs & e) && e != none && e != ref_ && e != return_)
.map!(e => e.to!string.strip('_'))
.map!(s => s.among!("safe", "trusted", "system", "nogc", "property") ? '@' ~ s : s)
.joiner(" ")
.to!string;
}
return funAttrStr;
}
importstd.traits;
导入标准元数据;
私有别名isSomeStringType(别名str)=isSomeString!(str类型);
模板转发成员(别名成员、符号…)
if(symbols.length>0&&all满足!(isSomeStringType,symbols))
{
静态if(symbols.length==1)
{
静态断言(hasMember!(typeof(member),符号[0]),
“无法分派:成员”“~member.stringof”~
“'不支持方法'”~symbols[0]~“'””;
enum forwardToMember=genWrapperMixin!(成员,符号[0]);
}
其他的
{
枚举forwardToMember=forwardToMember!(成员,符号[0])~forwardToMember!(成员,符号[1..$]);
}
}
私有枚举符号种类
{
功能,,
财产,,
模板函数,
fieldFunction,
领域
aliasableSym,
}
//丑陋的黑客,但没有其他方法可以做到这一点
私有模板isTemplateFunction(f…)
如果(f.length==1)
{
导入标准算法:中间,平衡点,可查找,计数;
静态if(!\u特征(isTemplate,f[0]))
{
枚举isTemplateFunction=false;
}
其他的
{
枚举fstr=f[0]。stringof;
//模板函数的.stringof的格式为()()
//因此,匹配括号的数量以确定它是否是模板函数
枚举isTemplateFunction=uu特征(isTemplate,f)
&&fstr.balancedParens(“(”,“)”)
&&(fstr.canFind(“如果”)
||fstr.count!(c=>cast(bool)c.within!('(','))==4);
}
}
私有模板getSymbolKind(聚合,字符串符号)
{
输入性病性状;
导入std.typetuple;
枚举getMemberMixin=“聚合。”~symbol;
//出现在Aggregate.tupleof中,因此它必须是一个字段
静态if(staticIndexOf!(符号,FieldNameTuple!聚合)>-1)
{
//检查它是常规字段还是函数指针
静态if(isSomeFunction!(mixin(getMemberMixin)))
枚举getSymbolKind=SymbolKind.fieldFunction;
其他的
枚举getSymbolKind=SymbolKind.field;
}
其他的
{
静态if(isSomeFunction!(mixin(getMemberMixin))
&&!\uuuu特征(isStaticFunction,mixin(getMemberMixin))
||isTemplateFunction!(mixin(getMemberMixin)))
{
静态if(isTemplateFunction!(mixin(getMemberMixin)))
枚举getSymbolKind=SymbolKind.templateFunction;
else静态if(functionAttributes!(mixin(getMemberMixin))&FunctionAttribute.property)
枚举getSymbolKind=SymbolKind.property;
其他的
枚举getSymbolKind=SymbolKind.function\u1;
}
//如果它不是成员函数/属性,那么它应该是可别名的静态符号
else静态if(uu traits(compiles,{alias}=alias!(mixin(getMemberMixin));}))
枚举getSymbolKind=SymbolKind.aliasableSym;
其他的
静态断言(0,“错误:”~Aggregate.stringof~“~symbol~”不是成员函数、字段或可别名符号”);
}
}
专用模板genWrapperMixin(别名成员,字符串符号)
{
导入标准算法:中间;
导入标准字符串:格式;
枚举symbolKind=getSymbolKind!(类型(成员),符号);
静态if(symbolKind.INTERGEN!(symbolKind.function,symbolKind.property,symbolKind.FIELDFONTION))
{
别名MethodType=FunctionTypeOf!(mixin(“成员”~symbol));
enum funAttrs=FunctionAttribute!MethodType;
enum methodIsStatic=uu traits(isStaticFunction,mixin(“成员”.~symbol));
enum funAttrStr=GetFunctionAttribute(funAttrs)~(methodIsStatic?“static”:“);
//解决问题14913
enum returnStr=funAttrs&FunctionAttribute.return?“return”:“”;
枚举genWrapperMixin=q{
%3美元
自动引用%2$s(ParameterTypeTuple!(FunctionTypeOf!(%1$s.%2$s))参数%4$s
{
导入标准功能:转发;
返回%1$s.%2$s(正向!参数);
}
}
.format(member.stringof、symbol、funatrstr、returnStr);
}
else静态if(symbolKind==symbolKind.templateFunction)
{
枚举genWrapperMixin=q{
模板%2$s(模板参数…)
{
自动引用%2$s(函数参数…)(自动引用函数参数)
{
导入标准功能:转发;
返回%1$s.%2$s!(模板参数)(前进!参数)
import std.stdio;
class B {
auto p1(T)(T arg) { writeln( "p1: ", arg ); }
auto p2(T, int C)(T s) { writeln( "p2: ", s, " / ", C); }
}
class C(T) {
T b = new T;
template opDispatch(string s) {
template opDispatch(TARGS...) {
auto opDispatch(ARGS...)(ARGS args) {
static if(TARGS.length) return mixin("b." ~ s ~ "!TARGS(args)");
else return mixin("b." ~ s ~ "(args)");
}
}
}
}
void main() {
auto b = new C!(B)();
b.p1("abc");
b.p2!(int, 10)(5);
}