2014-02-17 36 views
2

我在DMD行爲中發現了一些我不明白的東西。在班級方法中使用代表

我的代碼如下所示:

class C1 { 
    private static fun(alias f)() { 
     ; 
    } 
    public static void run() { 
     auto f = delegate bool(int x) {return true;} ; 
     fun!(f)(); 
     return; 
    } 
} 

而編譯器寫一個錯誤:

Error: template instance fun!(f) cannot use local 'f' as parameter to non-global template fun(alias f)() 

所以我要創造一流的委託字段使它全球:

class C1 { 
    private static fun(alias f)() { 
     ; 
    } 
    private static bool delegate(int) f; 
    public static void run() { 
     f = delegate bool(int x) {return true;} ; 
     fun!(f)(); 
     return; 
    } 
} 

此代碼編譯時沒有錯誤。但我不明白,爲什麼我們不能在方法中聲明委託?

+0

你的目標是什麼?我認爲可能有更好的方法來做到這一點。基本上'f'是一個可變的局部指向委託的指針(並且委託本身有一個上下文指針),所以你不能將它作爲模板參數傳遞 - 在編譯時必須知道這些參數。 –

回答

2

更新:這個問題是不是我原來想的那麼簡單。這是我認爲真的在發生。正如另一位評論者指出的那樣,我忘記了別名模板參數允許任何類型的符號被傳入,甚至是局部變量。在這種情況下,使用函數模板時,實例化模板需要一個指向其上下文的指針(run的主體),以便它可以訪問那些作爲別名參數傳入的局部變量(如代理f)。但是,fun已經是一個類的靜態成員,這意味着它已經有一個上下文指針(靜態類上下文)。現在,D編譯器的一個已知限制是它無法處理需要兩個或更多上下文指針的代理。 (這就是爲什麼它在錯誤消息中表示'非全局' - 全局函數模板因爲沒有上下文而起作用。)

第二個示例可用,因爲f不再是局部變量;它是一個靜態成員。它在run範圍內初始化的事實不會改變這一點。

請參見下面的問題:

希望有人與更多的編譯器的知識內可以證實這一診斷。

原來的答覆

(我原來的答覆說,該模板PARAM需要的是不可改變的,在編譯時已知以及不是一個委託(普通函數來代替)。這隻能解釋這個錯誤在編譯時,別名參數不需要具有已知的值,但是關於它的部分需要是常規函數而不是代表是正確的。)

這些解決方法來自我的原始答案仍適用:

聲明f在這些方式將確保它可以作爲一個模板PARAM傳遞:

// Not a delegate, not a local variable anymore (enum) 
enum f = function bool(int x) {return true;}; 

// "static" == not delegate 
static bool f(int x) { return true; } 
fun!(f)(); 

// Or pass it as a literal (inferred to be non-delegate) 
fun!((int x) => true); 

常規方法可以作爲模板PARAMS傳遞:

class C2 { 
    private static fun(alias f)() { 
     assert(f(1) == true); 
    } 
    private static bool g(int) { 
     return true; 
    } 
    public static void run() { 
     fun!(g)(); 
    } 
} 

或者把它作爲一個普通PARAM,而不是模板參數:

class C1 { 
    private static fun(bool delegate(int) f) { 
     assert(f(1) == true); 
    } 
    public static void run() { 
     auto f = delegate bool(int x) { return true; }; 
     fun(f); 
    } 
} 
+0

回答您關於目標的問題:我有一個基本的私有方法來獲取結構數組。我想要一組基於私有方法的公共方法,但以某種方式過濾數組。然後我得到了讓filter-function成爲私有方法成員的想法。然後我試着讓這個過濾函數依賴於公共方法的傳入值。這對我來說似乎是個好主意。 –

+0

是的!它應該像常規參數一樣傳遞。這是我搜索的答案。 –

+0

我改變了我對這個錯誤到底發生了什麼的看法。查看更新的答案 –

1

我沒有答案,但是這裏有一些想法不適合評論。

Error: template instance fun!(f) cannot use local 'f' as parameter to non-global template fun(alias f)()

你會注意到實際上有兩種方法可以解決這個問題。把'f'變成非局部變量,就像你做的那樣。或者使模板成爲全局。

這表明在將本地模板實例化爲局部變量時存在一些困難。我猜這意味着這是一個技術/實施的挑戰,而不是一個實際的限制(即不要這樣做,因爲......)。

更新:J. Miller未實現的是一個別名參數綁定到一個符號而不是一個值。在你的情況下,符號F是在編譯時已知的,因此這段代碼工作:

class C1 { 
    public static void run() { 
     auto f = delegate bool(int x) {return true;} ; 
     fun!(f)(); 
     return; 
    } 
} 

private void fun(alias f)() { 
    import std.stdio; 
    writeln(f(3)); 
} 

void main() { 
    new C1; 
    C1.run(); 
} 
+0

你是對的別名模板參數。這並不像我一開始想的那麼簡單。我會更新我的答案......謝謝。 –